Upgrade to OpenTelemetry Semantic Conventions v1.26.0

This commit is contained in:
Michael 2024-06-27 14:14:03 +02:00 committed by GitHub
parent 2f9905061e
commit 8cb1829698
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 558 additions and 217 deletions

View file

@ -5,6 +5,8 @@ description: "Traefik supports several tracing backends, including OpenTelemetry
# OpenTelemetry # OpenTelemetry
Traefik Proxy follows [official OpenTelemetry semantic conventions v1.26.0](https://github.com/open-telemetry/semantic-conventions/blob/v1.26.0/docs/http/http-spans.md).
To enable the OpenTelemetry tracer: To enable the OpenTelemetry tracer:
```yaml tab="File (YAML)" ```yaml tab="File (YAML)"

View file

@ -160,3 +160,28 @@ tracing:
```bash tab="CLI" ```bash tab="CLI"
--tracing.capturedResponseHeaders[0]=X-CustomHeader --tracing.capturedResponseHeaders[0]=X-CustomHeader
``` ```
#### `safeQueryParams`
_Optional, Default={}_
By default, all query parameters are redacted.
Defines the list of query parameters to not redact.
```yaml tab="File (YAML)"
tracing:
otlp:
safeQueryParams:
- bar
- buz
```
```toml tab="File (TOML)"
[tracing]
[tracing.otlp]
safeQueryParams = ["bar", "buz"]
```
```bash tab="CLI"
--tracing.otlp.safeQueryParams=bar,buz
```

View file

@ -1125,6 +1125,9 @@ TLS insecure skip verify (Default: ```false```)
`--tracing.otlp.http.tls.key`: `--tracing.otlp.http.tls.key`:
TLS key TLS key
`--tracing.safequeryparams`:
Query params to not redact.
`--tracing.samplerate`: `--tracing.samplerate`:
Sets the rate between 0.0 and 1.0 of requests to trace. (Default: ```1.000000```) Sets the rate between 0.0 and 1.0 of requests to trace. (Default: ```1.000000```)

View file

@ -1125,6 +1125,9 @@ TLS insecure skip verify (Default: ```false```)
`TRAEFIK_TRACING_OTLP_HTTP_TLS_KEY`: `TRAEFIK_TRACING_OTLP_HTTP_TLS_KEY`:
TLS key TLS key
`TRAEFIK_TRACING_SAFEQUERYPARAMS`:
Query params to not redact.
`TRAEFIK_TRACING_SAMPLERATE`: `TRAEFIK_TRACING_SAMPLERATE`:
Sets the rate between 0.0 and 1.0 of requests to trace. (Default: ```1.000000```) Sets the rate between 0.0 and 1.0 of requests to trace. (Default: ```1.000000```)

View file

@ -392,6 +392,7 @@
serviceName = "foobar" serviceName = "foobar"
capturedRequestHeaders = ["foobar", "foobar"] capturedRequestHeaders = ["foobar", "foobar"]
capturedResponseHeaders = ["foobar", "foobar"] capturedResponseHeaders = ["foobar", "foobar"]
safeQueryParams = ["foobar", "foobar"]
sampleRate = 42.0 sampleRate = 42.0
addInternals = true addInternals = true
[tracing.globalAttributes] [tracing.globalAttributes]

View file

@ -434,6 +434,9 @@ tracing:
capturedResponseHeaders: capturedResponseHeaders:
- foobar - foobar
- foobar - foobar
safeQueryParams:
- foobar
- foobar
sampleRate: 42 sampleRate: 42
addInternals: true addInternals: true
otlp: otlp:

32
go.mod
View file

@ -70,18 +70,18 @@ require (
github.com/unrolled/secure v1.0.9 github.com/unrolled/secure v1.0.9
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 v1.2.0 go.opentelemetry.io/collector/pdata v1.10.0
go.opentelemetry.io/contrib/propagators/autoprop v0.52.0 go.opentelemetry.io/contrib/propagators/autoprop v0.52.0
go.opentelemetry.io/otel v1.27.0 go.opentelemetry.io/otel v1.27.1-0.20240624175855-921eb701b175 // For security reason we need to follow semconv v1.26.0 and we can't wait for opentelemetry-go-sdk v1.28.0.
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.27.0 go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.27.1-0.20240624175855-921eb701b175 // For security reason we need to follow semconv v1.26.0 and we can't wait for opentelemetry-go-sdk v1.28.0.
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.27.0 go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.27.1-0.20240624175855-921eb701b175 // For security reason we need to follow semconv v1.26.0 and we can't wait for opentelemetry-go-sdk v1.28.0.
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.1-0.20240624175855-921eb701b175 // For security reason we need to follow semconv v1.26.0 and we can't wait for opentelemetry-go-sdk v1.28.0.
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.1-0.20240624175855-921eb701b175 // For security reason we need to follow semconv v1.26.0 and we can't wait for opentelemetry-go-sdk v1.28.0.
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.27.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.27.1-0.20240624175855-921eb701b175 // For security reason we need to follow semconv v1.26.0 and we can't wait for opentelemetry-go-sdk v1.28.0.
go.opentelemetry.io/otel/metric v1.27.0 go.opentelemetry.io/otel/metric v1.27.1-0.20240624175855-921eb701b175 // For security reason we need to follow semconv v1.26.0 and we can't wait for opentelemetry-go-sdk v1.28.0.
go.opentelemetry.io/otel/sdk v1.27.0 go.opentelemetry.io/otel/sdk v1.27.1-0.20240624175855-921eb701b175 // For security reason we need to follow semconv v1.26.0 and we can't wait for opentelemetry-go-sdk v1.28.0.
go.opentelemetry.io/otel/sdk/metric v1.27.0 go.opentelemetry.io/otel/sdk/metric v1.27.1-0.20240624175855-921eb701b175 // For security reason we need to follow semconv v1.26.0 and we can't wait for opentelemetry-go-sdk v1.28.0.
go.opentelemetry.io/otel/trace v1.27.0 go.opentelemetry.io/otel/trace v1.27.1-0.20240624175855-921eb701b175 // For security reason we need to follow semconv v1.26.0 and we can't wait for opentelemetry-go-sdk v1.28.0.
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f
golang.org/x/mod v0.18.0 golang.org/x/mod v0.18.0
golang.org/x/net v0.26.0 golang.org/x/net v0.26.0
@ -180,7 +180,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/v4 v4.0.2 // indirect github.com/go-jose/go-jose/v4 v4.0.2 // 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.4.1 // indirect github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-logr/zapr v1.3.0 // indirect github.com/go-logr/zapr v1.3.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-ole/go-ole v1.2.6 // indirect
@ -329,7 +329,7 @@ require (
go.opentelemetry.io/contrib/propagators/b3 v1.27.0 // indirect go.opentelemetry.io/contrib/propagators/b3 v1.27.0 // indirect
go.opentelemetry.io/contrib/propagators/jaeger v1.27.0 // indirect go.opentelemetry.io/contrib/propagators/jaeger v1.27.0 // indirect
go.opentelemetry.io/contrib/propagators/ot v1.27.0 // indirect go.opentelemetry.io/contrib/propagators/ot v1.27.0 // indirect
go.opentelemetry.io/proto/otlp v1.2.0 // indirect go.opentelemetry.io/proto/otlp v1.3.1 // indirect
go.uber.org/atomic v1.11.0 // indirect go.uber.org/atomic v1.11.0 // indirect
go.uber.org/mock v0.4.0 // indirect go.uber.org/mock v0.4.0 // indirect
go.uber.org/multierr v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect
@ -342,9 +342,9 @@ require (
golang.org/x/term v0.21.0 // indirect golang.org/x/term v0.21.0 // indirect
google.golang.org/api v0.172.0 // indirect google.golang.org/api v0.172.0 // indirect
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240520151616-dc85e6b867a5 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240624140628-dc46fd24d27d // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240515191416-fc5f0ca64291 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240624140628-dc46fd24d27d // indirect
google.golang.org/protobuf v1.34.1 // indirect google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/h2non/gock.v1 v1.0.16 // indirect gopkg.in/h2non/gock.v1 v1.0.16 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect

64
go.sum
View file

@ -348,8 +348,8 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG
github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA=
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.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.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.4.2/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.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=
@ -1182,8 +1182,8 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.opentelemetry.io/collector/pdata v1.2.0 h1:N6VdyEFYJyoHIKqHd0F372eNVD5b+AbH0ZQf7Z2jJ9I= go.opentelemetry.io/collector/pdata v1.10.0 h1:oLyPLGvPTQrcRT64ZVruwvmH/u3SHTfNo01pteS4WOE=
go.opentelemetry.io/collector/pdata v1.2.0/go.mod h1:mKXb6527Syb8PT4P9CZOJNbkuHOHjjGTZNNwSKESJhc= go.opentelemetry.io/collector/pdata v1.10.0/go.mod h1:IHxHsp+Jq/xfjORQMDJjSH6jvedOSTOyu3nbxqhWSYE=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw=
go.opentelemetry.io/contrib/propagators/autoprop v0.52.0 h1:xyRih6jMB0vroMSRdBE+uyKx20BclB/bybJt/LaCxmY= go.opentelemetry.io/contrib/propagators/autoprop v0.52.0 h1:xyRih6jMB0vroMSRdBE+uyKx20BclB/bybJt/LaCxmY=
@ -1196,29 +1196,29 @@ go.opentelemetry.io/contrib/propagators/jaeger v1.27.0 h1:tJPpZAEsihJgRTnXrPjY3r
go.opentelemetry.io/contrib/propagators/jaeger v1.27.0/go.mod h1:5uPAMHJnlTktQbCCdWSX5PfK8CocD25mycIsZV/iFiU= go.opentelemetry.io/contrib/propagators/jaeger v1.27.0/go.mod h1:5uPAMHJnlTktQbCCdWSX5PfK8CocD25mycIsZV/iFiU=
go.opentelemetry.io/contrib/propagators/ot v1.27.0 h1:xFPqk7ntRR87dqvl6RfeHiq9UlE8mPSuL6Dtr/zysL8= go.opentelemetry.io/contrib/propagators/ot v1.27.0 h1:xFPqk7ntRR87dqvl6RfeHiq9UlE8mPSuL6Dtr/zysL8=
go.opentelemetry.io/contrib/propagators/ot v1.27.0/go.mod h1:nVLTPrDlSZPoVdeWRmpWBwxA73TYL6XLkC4bj72jvmg= go.opentelemetry.io/contrib/propagators/ot v1.27.0/go.mod h1:nVLTPrDlSZPoVdeWRmpWBwxA73TYL6XLkC4bj72jvmg=
go.opentelemetry.io/otel v1.27.0 h1:9BZoF3yMK/O1AafMiQTVu0YDj5Ea4hPhxCs7sGva+cg= go.opentelemetry.io/otel v1.27.1-0.20240624175855-921eb701b175 h1:2aQYN3ZllvztGtSIFNT2xGMrwsbPkGXj0O+KgPVsq5A=
go.opentelemetry.io/otel v1.27.0/go.mod h1:DMpAK8fzYRzs+bi3rS5REupisuqTheUlSZJ1WnZaPAQ= go.opentelemetry.io/otel v1.27.1-0.20240624175855-921eb701b175/go.mod h1:sAYY1kDqq6Qgmu9OdUrtIhBJAVKevM27kmSzEkEyyBg=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.27.0 h1:bFgvUr3/O4PHj3VQcFEuYKvRZJX1SJDQ+11JXuSB3/w= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.27.1-0.20240624175855-921eb701b175 h1:awu+mcY8Zh17gkaxch+AY59ZEeZHsct61kce/JUa/Ho=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.27.0/go.mod h1:xJntEd2KL6Qdg5lwp97HMLQDVeAhrYxmzFseAMDPQ8I= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.27.1-0.20240624175855-921eb701b175/go.mod h1:wwHMT54YgLNroOkp4+XK7PRqCez5DtQayTBR9Wf1CEA=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.27.0 h1:CIHWikMsN3wO+wq1Tp5VGdVRTcON+DmOJSfDjXypKOc= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.27.1-0.20240624175855-921eb701b175 h1:nNu+y3xs12BTRqNVciOBdq1bwUpqHJFs26lhXXnO8/0=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.27.0/go.mod h1:TNupZ6cxqyFEpLXAZW7On+mLFL0/g0TE3unIYL91xWc= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.27.1-0.20240624175855-921eb701b175/go.mod h1:/TESptXGTu8vZX8i19t1TSU4PGo9+gT9pGK/UNAea9I=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0 h1:R9DE4kQ4k+YtfLI2ULwX82VtNQ2J8yZmA7ZIF/D+7Mc= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.1-0.20240624175855-921eb701b175 h1:ihrS8VlMvzPDy1QJ9yIsrKpcso6XnADVrj33wWxRG6k=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0/go.mod h1:OQFyQVrDlbe+R7xrEyDr/2Wr67Ol0hRUgsfA+V5A95s= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.1-0.20240624175855-921eb701b175/go.mod h1:O6p37S657iklDAWQZrzkHeyOooL0TRG7ADP6jZ1RpF8=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 h1:qFffATk0X+HD+f1Z8lswGiOQYKHRlzfmdJm0wEaVrFA= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.1-0.20240624175855-921eb701b175 h1:qk6WZWPTf1MDvgLRCECyzbUzugNp2Ybc11fnrj6L/t4=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0/go.mod h1:MOiCmryaYtc+V0Ei+Tx9o5S1ZjA7kzLucuVuyzBZloQ= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.1-0.20240624175855-921eb701b175/go.mod h1:A5CvQA6TBgKbMXLU3YrV9WB2m5xQYB50/PLkW1nJA8k=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.27.0 h1:QY7/0NeRPKlzusf40ZE4t1VlMKbqSNT7cJRYzWuja0s= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.27.1-0.20240624175855-921eb701b175 h1:l47wCNFvbEdVi0U3Ojf5yD6QhrNjuK2N46N9tiCzpNE=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.27.0/go.mod h1:HVkSiDhTM9BoUJU8qE6j2eSWLLXvi1USXjyd2BXT8PY= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.27.1-0.20240624175855-921eb701b175/go.mod h1:vS4rxlVsjAdnvN34PmMKVPKZdQrKVxRw6Tz6qQ+NsY8=
go.opentelemetry.io/otel/metric v1.27.0 h1:hvj3vdEKyeCi4YaYfNjv2NUje8FqKqUY8IlF0FxV/ik= go.opentelemetry.io/otel/metric v1.27.1-0.20240624175855-921eb701b175 h1:YGLAewt2Wr/DFRQI6OjqqZ31B+CO3W1bcDWhsIL7r98=
go.opentelemetry.io/otel/metric v1.27.0/go.mod h1:mVFgmRlhljgBiuk/MP/oKylr4hs85GZAylncepAX/ak= go.opentelemetry.io/otel/metric v1.27.1-0.20240624175855-921eb701b175/go.mod h1:YHVa4iPQFl9x0kF/Pxk1MYAbroRbl7zK+vT34w7VsCA=
go.opentelemetry.io/otel/sdk v1.27.0 h1:mlk+/Y1gLPLn84U4tI8d3GNJmGT/eXe3ZuOXN9kTWmI= go.opentelemetry.io/otel/sdk v1.27.1-0.20240624175855-921eb701b175 h1:QdXgh+39hJwRYYQ3OgcI4SMawt/rPBgmQdtZYGxzdq8=
go.opentelemetry.io/otel/sdk v1.27.0/go.mod h1:Ha9vbLwJE6W86YstIywK2xFfPjbWlCuwPtMkKdz/Y4A= go.opentelemetry.io/otel/sdk v1.27.1-0.20240624175855-921eb701b175/go.mod h1:Ru3JMbgJMftQARx7nhi0IJotnL2n8bv61IOrAgFpd+s=
go.opentelemetry.io/otel/sdk/metric v1.27.0 h1:5uGNOlpXi+Hbo/DRoI31BSb1v+OGcpv2NemcCrOL8gI= go.opentelemetry.io/otel/sdk/metric v1.27.1-0.20240624175855-921eb701b175 h1:GYxFdqdupCe5BEORUuWvNMRKeZliRLK8INKCgGzYLRA=
go.opentelemetry.io/otel/sdk/metric v1.27.0/go.mod h1:we7jJVrYN2kh3mVBlswtPU22K0SA+769l93J6bsyvqw= go.opentelemetry.io/otel/sdk/metric v1.27.1-0.20240624175855-921eb701b175/go.mod h1:SRwqsyIihvNIPKOVe1CqC4owsJX2vv63U5op9Axd4fI=
go.opentelemetry.io/otel/trace v1.27.0 h1:IqYb813p7cmbHk0a5y6pD5JPakbVfftRXABGt5/Rscw= go.opentelemetry.io/otel/trace v1.27.1-0.20240624175855-921eb701b175 h1:1y2KlY7+gTBn4GZa2yMKqgcb4H2KIOrBSSrG4esCC3g=
go.opentelemetry.io/otel/trace v1.27.0/go.mod h1:6RiD1hkAprV4/q+yd2ln1HG9GoPx39SuvvstaLBl+l4= go.opentelemetry.io/otel/trace v1.27.1-0.20240624175855-921eb701b175/go.mod h1:6RiD1hkAprV4/q+yd2ln1HG9GoPx39SuvvstaLBl+l4=
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.2.0 h1:pVeZGk7nXDC9O2hncA6nHldxEjm6LByfA2aN8IOkz94= go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
go.opentelemetry.io/proto/otlp v1.2.0/go.mod h1:gGpR8txAl5M03pDhMC79G6SdqNV26naRm/KDsgaHD8A= go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
@ -1547,10 +1547,10 @@ google.golang.org/genproto v0.0.0-20200806141610-86f49bd18e98/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20211021150943-2b146023228c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211021150943-2b146023228c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY= google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY=
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo=
google.golang.org/genproto/googleapis/api v0.0.0-20240520151616-dc85e6b867a5 h1:P8OJ/WCl/Xo4E4zoe4/bifHpSmmKwARqyqE4nW6J2GQ= google.golang.org/genproto/googleapis/api v0.0.0-20240624140628-dc46fd24d27d h1:Aqf0fiIdUQEj0Gn9mKFFXoQfTTEaNopWpfVyYADxiSg=
google.golang.org/genproto/googleapis/api v0.0.0-20240520151616-dc85e6b867a5/go.mod h1:RGnPtTG7r4i8sPlNyDeikXF99hMM+hN6QMm4ooG9g2g= google.golang.org/genproto/googleapis/api v0.0.0-20240624140628-dc46fd24d27d/go.mod h1:Od4k8V1LQSizPRUK4OzZ7TBE/20k+jPczUDAEyvn69Y=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240515191416-fc5f0ca64291 h1:AgADTJarZTBqgjiUzRgfaBchgYB3/WFTC80GPwsMcRI= google.golang.org/genproto/googleapis/rpc v0.0.0-20240624140628-dc46fd24d27d h1:k3zyW3BYYR30e8v3x0bTDdE9vpYFjZHK+HcyqkrppWk=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240515191416-fc5f0ca64291/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= google.golang.org/genproto/googleapis/rpc v0.0.0-20240624140628-dc46fd24d27d/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
@ -1588,8 +1588,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View file

@ -7,7 +7,7 @@ services:
volumes: volumes:
- ./fixtures/tracing/tempo.yaml:/etc/tempo.yaml - ./fixtures/tracing/tempo.yaml:/etc/tempo.yaml
otel-collector: otel-collector:
image: otel/opentelemetry-collector-contrib:0.89.0 image: otel/opentelemetry-collector-contrib:0.103.0
volumes: volumes:
- ./fixtures/tracing/otel-collector-config.yaml:/etc/otelcol-contrib/config.yaml - ./fixtures/tracing/otel-collector-config.yaml:/etc/otelcol-contrib/config.yaml
whoami: whoami:

View file

@ -2,7 +2,9 @@ package integration
import ( import (
"encoding/json" "encoding/json"
"fmt"
"io" "io"
"net"
"net/http" "net/http"
"net/url" "net/url"
"os" "os"
@ -96,27 +98,46 @@ func (s *TracingSuite) TestOpentelemetryBasic_HTTP() {
{ {
"batches.0.scopeSpans.0.scope.name": "github.com/traefik/traefik", "batches.0.scopeSpans.0.scope.name": "github.com/traefik/traefik",
"batches.0.scopeSpans.0.spans.0.name": "EntryPoint", "batches.0.scopeSpans.0.spans.0.name": "ReverseProxy",
"batches.0.scopeSpans.0.spans.0.kind": "SPAN_KIND_SERVER", "batches.0.scopeSpans.0.spans.0.kind": "SPAN_KIND_CLIENT",
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.request.method\").value.stringValue": "GET", "batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.request.method\").value.stringValue": "GET",
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"entry_point\").value.stringValue": "web", "batches.0.scopeSpans.0.spans.0.attributes.#(key=\"network.protocol.version\").value.stringValue": "1.1",
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"url.path\").value.stringValue": "/basic", "batches.0.scopeSpans.0.spans.0.attributes.#(key=\"url.full\").value.stringValue": fmt.Sprintf("http://%s/basic", net.JoinHostPort(s.whoamiIP, "80")),
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1",
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"network.peer.address\").value.stringValue": s.whoamiIP,
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"network.peer.port\").value.intValue": "80",
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"server.address\").value.stringValue": s.whoamiIP,
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"server.port\").value.intValue": "80",
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.response.status_code\").value.intValue": "200", "batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.response.status_code\").value.intValue": "200",
"batches.0.scopeSpans.0.spans.1.name": "Router", "batches.0.scopeSpans.0.spans.1.name": "Metrics",
"batches.0.scopeSpans.0.spans.1.kind": "SPAN_KIND_INTERNAL", "batches.0.scopeSpans.0.spans.1.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.router.name\").value.stringValue": "router0@file", "batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "metrics-service",
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.service.name\").value.stringValue": "service0@file",
"batches.0.scopeSpans.0.spans.2.name": "Service", "batches.0.scopeSpans.0.spans.2.name": "Service",
"batches.0.scopeSpans.0.spans.2.kind": "SPAN_KIND_INTERNAL", "batches.0.scopeSpans.0.spans.2.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.2.attributes.#(key=\"traefik.service.name\").value.stringValue": "service0@file", "batches.0.scopeSpans.0.spans.2.attributes.#(key=\"traefik.service.name\").value.stringValue": "service0@file",
"batches.0.scopeSpans.0.spans.3.name": "ReverseProxy", "batches.0.scopeSpans.0.spans.3.name": "Router",
"batches.0.scopeSpans.0.spans.3.kind": "SPAN_KIND_CLIENT", "batches.0.scopeSpans.0.spans.3.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"url.scheme\").value.stringValue": "http", "batches.0.scopeSpans.0.spans.3.attributes.#(key=\"traefik.service.name\").value.stringValue": "service0@file",
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"http.response.status_code\").value.intValue": "200", "batches.0.scopeSpans.0.spans.3.attributes.#(key=\"traefik.router.name\").value.stringValue": "router0@file",
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1", "batches.0.scopeSpans.0.spans.3.attributes.#(key=\"http.route\").value.stringValue": "Path(`/basic`)",
"batches.0.scopeSpans.0.spans.4.name": "Metrics",
"batches.0.scopeSpans.0.spans.4.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "metrics-entrypoint",
"batches.0.scopeSpans.0.spans.5.name": "EntryPoint",
"batches.0.scopeSpans.0.spans.5.kind": "SPAN_KIND_SERVER",
"batches.0.scopeSpans.0.spans.5.attributes.#(key=\"entry_point\").value.stringValue": "web",
"batches.0.scopeSpans.0.spans.5.attributes.#(key=\"http.request.method\").value.stringValue": "GET",
"batches.0.scopeSpans.0.spans.5.attributes.#(key=\"url.path\").value.stringValue": "/basic",
"batches.0.scopeSpans.0.spans.5.attributes.#(key=\"url.query\").value.stringValue": "",
"batches.0.scopeSpans.0.spans.5.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1",
"batches.0.scopeSpans.0.spans.5.attributes.#(key=\"server.address\").value.stringValue": "127.0.0.1:8000",
"batches.0.scopeSpans.0.spans.5.attributes.#(key=\"network.peer.address\").value.stringValue": "127.0.0.1",
"batches.0.scopeSpans.0.spans.5.attributes.#(key=\"http.response.status_code\").value.intValue": "200",
}, },
} }
@ -145,27 +166,35 @@ func (s *TracingSuite) TestOpentelemetryBasic_gRPC() {
{ {
"batches.0.scopeSpans.0.scope.name": "github.com/traefik/traefik", "batches.0.scopeSpans.0.scope.name": "github.com/traefik/traefik",
"batches.0.scopeSpans.0.spans.0.name": "EntryPoint", "batches.0.scopeSpans.0.spans.0.name": "ReverseProxy",
"batches.0.scopeSpans.0.spans.0.kind": "SPAN_KIND_SERVER", "batches.0.scopeSpans.0.spans.0.kind": "SPAN_KIND_CLIENT",
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.request.method\").value.stringValue": "GET", "batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.request.method\").value.stringValue": "GET",
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"entry_point\").value.stringValue": "web", "batches.0.scopeSpans.0.spans.0.attributes.#(key=\"network.protocol.version\").value.stringValue": "1.1",
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"url.path\").value.stringValue": "/basic", "batches.0.scopeSpans.0.spans.0.attributes.#(key=\"url.full\").value.stringValue": fmt.Sprintf("http://%s/basic", net.JoinHostPort(s.whoamiIP, "80")),
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1",
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"network.peer.address\").value.stringValue": s.whoamiIP,
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"network.peer.port\").value.intValue": "80",
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"server.address\").value.stringValue": s.whoamiIP,
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"server.port\").value.intValue": "80",
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.response.status_code\").value.intValue": "200", "batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.response.status_code\").value.intValue": "200",
"batches.0.scopeSpans.0.spans.1.name": "Router", "batches.0.scopeSpans.0.spans.1.name": "Metrics",
"batches.0.scopeSpans.0.spans.1.kind": "SPAN_KIND_INTERNAL", "batches.0.scopeSpans.0.spans.1.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.router.name\").value.stringValue": "router0@file", "batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "metrics-service",
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.service.name\").value.stringValue": "service0@file",
"batches.0.scopeSpans.0.spans.2.name": "Service", "batches.0.scopeSpans.0.spans.2.name": "Service",
"batches.0.scopeSpans.0.spans.2.kind": "SPAN_KIND_INTERNAL", "batches.0.scopeSpans.0.spans.2.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.2.attributes.#(key=\"traefik.service.name\").value.stringValue": "service0@file", "batches.0.scopeSpans.0.spans.2.attributes.#(key=\"traefik.service.name\").value.stringValue": "service0@file",
"batches.0.scopeSpans.0.spans.3.name": "ReverseProxy", "batches.0.scopeSpans.0.spans.3.name": "Router",
"batches.0.scopeSpans.0.spans.3.kind": "SPAN_KIND_CLIENT", "batches.0.scopeSpans.0.spans.3.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"url.scheme\").value.stringValue": "http", "batches.0.scopeSpans.0.spans.3.attributes.#(key=\"traefik.service.name\").value.stringValue": "service0@file",
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"http.response.status_code\").value.intValue": "200", "batches.0.scopeSpans.0.spans.3.attributes.#(key=\"traefik.router.name\").value.stringValue": "router0@file",
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1", "batches.0.scopeSpans.0.spans.3.attributes.#(key=\"http.route\").value.stringValue": "Path(`/basic`)",
"batches.0.scopeSpans.0.spans.4.name": "Metrics",
"batches.0.scopeSpans.0.spans.4.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "metrics-entrypoint",
}, },
} }
@ -215,54 +244,75 @@ func (s *TracingSuite) TestOpentelemetryRateLimit() {
{ {
"batches.0.scopeSpans.0.scope.name": "github.com/traefik/traefik", "batches.0.scopeSpans.0.scope.name": "github.com/traefik/traefik",
"batches.0.scopeSpans.0.spans.0.name": "EntryPoint", "batches.0.scopeSpans.0.spans.0.name": "RateLimiter",
"batches.0.scopeSpans.0.spans.0.kind": "SPAN_KIND_SERVER", "batches.0.scopeSpans.0.spans.0.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.request.method\").value.stringValue": "GET", "batches.0.scopeSpans.0.spans.0.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "ratelimit-1@file",
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"entry_point\").value.stringValue": "web",
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"url.path\").value.stringValue": "/ratelimit",
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.response.status_code\").value.intValue": "200",
"batches.0.scopeSpans.0.spans.1.name": "Router", "batches.0.scopeSpans.0.spans.1.name": "Retry",
"batches.0.scopeSpans.0.spans.1.kind": "SPAN_KIND_INTERNAL", "batches.0.scopeSpans.0.spans.1.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.router.name\").value.stringValue": "router1@file", "batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file",
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.service.name\").value.stringValue": "service1@file",
"batches.0.scopeSpans.0.spans.2.name": "Retry", "batches.0.scopeSpans.0.spans.2.name": "RateLimiter",
"batches.0.scopeSpans.0.spans.2.kind": "SPAN_KIND_INTERNAL", "batches.0.scopeSpans.0.spans.2.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.2.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file", "batches.0.scopeSpans.0.spans.2.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "ratelimit-1@file",
"batches.0.scopeSpans.0.spans.3.name": "RateLimiter", "batches.0.scopeSpans.0.spans.3.name": "Retry",
"batches.0.scopeSpans.0.spans.3.kind": "SPAN_KIND_INTERNAL", "batches.0.scopeSpans.0.spans.3.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "ratelimit-1@file", "batches.0.scopeSpans.0.spans.3.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file",
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"http.request.resend_count\").value.intValue": "1",
"batches.0.scopeSpans.0.spans.4.name": "Service", "batches.0.scopeSpans.0.spans.4.name": "RateLimiter",
"batches.0.scopeSpans.0.spans.4.kind": "SPAN_KIND_INTERNAL", "batches.0.scopeSpans.0.spans.4.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"traefik.service.name\").value.stringValue": "service1@file", "batches.0.scopeSpans.0.spans.4.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "ratelimit-1@file",
"batches.0.scopeSpans.0.spans.5.name": "ReverseProxy", "batches.0.scopeSpans.0.spans.5.name": "Retry",
"batches.0.scopeSpans.0.spans.5.kind": "SPAN_KIND_CLIENT", "batches.0.scopeSpans.0.spans.5.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.5.attributes.#(key=\"url.scheme\").value.stringValue": "http", "batches.0.scopeSpans.0.spans.5.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file",
"batches.0.scopeSpans.0.spans.5.attributes.#(key=\"http.response.status_code\").value.intValue": "200", "batches.0.scopeSpans.0.spans.5.attributes.#(key=\"http.request.resend_count\").value.intValue": "2",
"batches.0.scopeSpans.0.spans.5.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1",
"batches.0.scopeSpans.0.spans.6.name": "Router",
"batches.0.scopeSpans.0.spans.6.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.6.attributes.#(key=\"traefik.service.name\").value.stringValue": "service1@file",
"batches.0.scopeSpans.0.spans.6.attributes.#(key=\"traefik.router.name\").value.stringValue": "router1@file",
"batches.0.scopeSpans.0.spans.6.attributes.#(key=\"http.route\").value.stringValue": "Path(`/ratelimit`)",
"batches.0.scopeSpans.0.spans.7.name": "Metrics",
"batches.0.scopeSpans.0.spans.7.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "metrics-entrypoint",
"batches.0.scopeSpans.0.spans.8.name": "EntryPoint",
"batches.0.scopeSpans.0.spans.8.kind": "SPAN_KIND_SERVER",
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"entry_point\").value.stringValue": "web",
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"http.request.method\").value.stringValue": "GET",
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"url.path\").value.stringValue": "/ratelimit",
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"url.query\").value.stringValue": "",
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1",
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"server.address\").value.stringValue": "127.0.0.1:8000",
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"network.peer.address\").value.stringValue": "127.0.0.1",
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"http.response.status_code\").value.intValue": "429",
}, },
{ {
"batches.0.scopeSpans.0.scope.name": "github.com/traefik/traefik", "batches.0.scopeSpans.0.scope.name": "github.com/traefik/traefik",
"batches.0.scopeSpans.0.spans.0.name": "EntryPoint", "batches.0.scopeSpans.0.spans.0.name": "ReverseProxy",
"batches.0.scopeSpans.0.spans.0.kind": "SPAN_KIND_SERVER", "batches.0.scopeSpans.0.spans.0.kind": "SPAN_KIND_CLIENT",
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.request.method\").value.stringValue": "GET", "batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.request.method\").value.stringValue": "GET",
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"entry_point\").value.stringValue": "web", "batches.0.scopeSpans.0.spans.0.attributes.#(key=\"network.protocol.version\").value.stringValue": "1.1",
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"url.path\").value.stringValue": "/ratelimit", "batches.0.scopeSpans.0.spans.0.attributes.#(key=\"url.full\").value.stringValue": fmt.Sprintf("http://%s/ratelimit", net.JoinHostPort(s.whoamiIP, "80")),
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.response.status_code\").value.intValue": "429", "batches.0.scopeSpans.0.spans.0.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1",
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"network.peer.address\").value.stringValue": s.whoamiIP,
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"network.peer.port\").value.intValue": "80",
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"server.address\").value.stringValue": s.whoamiIP,
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"server.port\").value.intValue": "80",
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.response.status_code\").value.intValue": "200",
"batches.0.scopeSpans.0.spans.1.name": "Router", "batches.0.scopeSpans.0.spans.1.name": "Metrics",
"batches.0.scopeSpans.0.spans.1.kind": "SPAN_KIND_INTERNAL", "batches.0.scopeSpans.0.spans.1.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.router.name\").value.stringValue": "router1@file", "batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "metrics-service",
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.service.name\").value.stringValue": "service1@file",
"batches.0.scopeSpans.0.spans.2.name": "Retry", "batches.0.scopeSpans.0.spans.2.name": "Service",
"batches.0.scopeSpans.0.spans.2.kind": "SPAN_KIND_INTERNAL", "batches.0.scopeSpans.0.spans.2.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.2.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file", "batches.0.scopeSpans.0.spans.2.attributes.#(key=\"traefik.service.name\").value.stringValue": "service1@file",
"batches.0.scopeSpans.0.spans.3.name": "RateLimiter", "batches.0.scopeSpans.0.spans.3.name": "RateLimiter",
"batches.0.scopeSpans.0.spans.3.kind": "SPAN_KIND_INTERNAL", "batches.0.scopeSpans.0.spans.3.kind": "SPAN_KIND_INTERNAL",
@ -271,20 +321,27 @@ func (s *TracingSuite) TestOpentelemetryRateLimit() {
"batches.0.scopeSpans.0.spans.4.name": "Retry", "batches.0.scopeSpans.0.spans.4.name": "Retry",
"batches.0.scopeSpans.0.spans.4.kind": "SPAN_KIND_INTERNAL", "batches.0.scopeSpans.0.spans.4.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file", "batches.0.scopeSpans.0.spans.4.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file",
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"http.resend_count\").value.intValue": "1",
"batches.0.scopeSpans.0.spans.5.name": "RateLimiter", "batches.0.scopeSpans.0.spans.5.name": "Router",
"batches.0.scopeSpans.0.spans.5.kind": "SPAN_KIND_INTERNAL", "batches.0.scopeSpans.0.spans.5.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.5.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "ratelimit-1@file", "batches.0.scopeSpans.0.spans.5.attributes.#(key=\"traefik.service.name\").value.stringValue": "service1@file",
"batches.0.scopeSpans.0.spans.5.attributes.#(key=\"traefik.router.name\").value.stringValue": "router1@file",
"batches.0.scopeSpans.0.spans.5.attributes.#(key=\"http.route\").value.stringValue": "Path(`/ratelimit`)",
"batches.0.scopeSpans.0.spans.6.name": "Retry", "batches.0.scopeSpans.0.spans.6.name": "Metrics",
"batches.0.scopeSpans.0.spans.6.kind": "SPAN_KIND_INTERNAL", "batches.0.scopeSpans.0.spans.6.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.6.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file", "batches.0.scopeSpans.0.spans.6.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "metrics-entrypoint",
"batches.0.scopeSpans.0.spans.6.attributes.#(key=\"http.resend_count\").value.intValue": "2",
"batches.0.scopeSpans.0.spans.7.name": "RateLimiter", "batches.0.scopeSpans.0.spans.7.name": "EntryPoint",
"batches.0.scopeSpans.0.spans.7.kind": "SPAN_KIND_INTERNAL", "batches.0.scopeSpans.0.spans.7.kind": "SPAN_KIND_SERVER",
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "ratelimit-1@file", "batches.0.scopeSpans.0.spans.7.attributes.#(key=\"entry_point\").value.stringValue": "web",
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"http.request.method\").value.stringValue": "GET",
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"url.path\").value.stringValue": "/ratelimit",
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"url.query\").value.stringValue": "",
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1",
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"server.address\").value.stringValue": "127.0.0.1:8000",
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"network.peer.address\").value.stringValue": "127.0.0.1",
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"http.response.status_code\").value.intValue": "200",
}, },
} }
@ -312,60 +369,102 @@ func (s *TracingSuite) TestOpentelemetryRetry() {
{ {
"batches.0.scopeSpans.0.scope.name": "github.com/traefik/traefik", "batches.0.scopeSpans.0.scope.name": "github.com/traefik/traefik",
"batches.0.scopeSpans.0.spans.0.name": "EntryPoint", "batches.0.scopeSpans.0.spans.0.name": "ReverseProxy",
"batches.0.scopeSpans.0.spans.0.kind": "SPAN_KIND_CLIENT",
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.request.method\").value.stringValue": "GET", "batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.request.method\").value.stringValue": "GET",
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"url.path\").value.stringValue": "/retry", "batches.0.scopeSpans.0.spans.0.attributes.#(key=\"network.protocol.version\").value.stringValue": "1.1",
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"url.full\").value.stringValue": fmt.Sprintf("http://%s/retry", net.JoinHostPort(s.whoamiIP, "81")),
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1",
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"network.peer.address\").value.stringValue": s.whoamiIP,
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"network.peer.port\").value.intValue": "81",
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"server.address\").value.stringValue": s.whoamiIP,
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"server.port\").value.intValue": "81",
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.response.status_code\").value.intValue": "502", "batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.response.status_code\").value.intValue": "502",
"batches.0.scopeSpans.0.spans.0.status.code": "STATUS_CODE_ERROR", "batches.0.scopeSpans.0.spans.0.status.code": "STATUS_CODE_ERROR",
"batches.0.scopeSpans.0.spans.1.name": "Router", "batches.0.scopeSpans.0.spans.1.name": "Metrics",
"batches.0.scopeSpans.0.spans.1.kind": "SPAN_KIND_INTERNAL", "batches.0.scopeSpans.0.spans.1.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.service.name\").value.stringValue": "service2@file", "batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "metrics-service",
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.router.name\").value.stringValue": "router2@file",
"batches.0.scopeSpans.0.spans.2.name": "Retry", "batches.0.scopeSpans.0.spans.2.name": "Service",
"batches.0.scopeSpans.0.spans.2.kind": "SPAN_KIND_INTERNAL", "batches.0.scopeSpans.0.spans.2.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.2.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file", "batches.0.scopeSpans.0.spans.2.attributes.#(key=\"traefik.service.name\").value.stringValue": "service2@file",
"batches.0.scopeSpans.0.spans.3.name": "Service", "batches.0.scopeSpans.0.spans.3.name": "Retry",
"batches.0.scopeSpans.0.spans.3.kind": "SPAN_KIND_INTERNAL", "batches.0.scopeSpans.0.spans.3.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"traefik.service.name\").value.stringValue": "service2@file", "batches.0.scopeSpans.0.spans.3.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file",
"batches.0.scopeSpans.0.spans.4.name": "ReverseProxy", "batches.0.scopeSpans.0.spans.4.name": "ReverseProxy",
"batches.0.scopeSpans.0.spans.4.kind": "SPAN_KIND_CLIENT", "batches.0.scopeSpans.0.spans.4.kind": "SPAN_KIND_CLIENT",
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"url.scheme\").value.stringValue": "http", "batches.0.scopeSpans.0.spans.4.attributes.#(key=\"http.request.method\").value.stringValue": "GET",
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"http.response.status_code\").value.intValue": "502", "batches.0.scopeSpans.0.spans.4.attributes.#(key=\"network.protocol.version\").value.stringValue": "1.1",
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"url.full\").value.stringValue": fmt.Sprintf("http://%s/retry", net.JoinHostPort(s.whoamiIP, "81")),
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1", "batches.0.scopeSpans.0.spans.4.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1",
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"network.peer.address\").value.stringValue": s.whoamiIP,
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"network.peer.port\").value.intValue": "81",
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"server.address\").value.stringValue": s.whoamiIP,
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"server.port\").value.intValue": "81",
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"http.response.status_code\").value.intValue": "502",
"batches.0.scopeSpans.0.spans.4.status.code": "STATUS_CODE_ERROR",
"batches.0.scopeSpans.0.spans.5.name": "Retry", "batches.0.scopeSpans.0.spans.5.name": "Metrics",
"batches.0.scopeSpans.0.spans.5.kind": "SPAN_KIND_INTERNAL", "batches.0.scopeSpans.0.spans.5.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.5.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file", "batches.0.scopeSpans.0.spans.5.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "metrics-service",
"batches.0.scopeSpans.0.spans.5.attributes.#(key=\"http.resend_count\").value.intValue": "1",
"batches.0.scopeSpans.0.spans.6.name": "Service", "batches.0.scopeSpans.0.spans.6.name": "Service",
"batches.0.scopeSpans.0.spans.6.kind": "SPAN_KIND_INTERNAL", "batches.0.scopeSpans.0.spans.6.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.6.attributes.#(key=\"traefik.service.name\").value.stringValue": "service2@file", "batches.0.scopeSpans.0.spans.6.attributes.#(key=\"traefik.service.name\").value.stringValue": "service2@file",
"batches.0.scopeSpans.0.spans.7.name": "ReverseProxy", "batches.0.scopeSpans.0.spans.7.name": "Retry",
"batches.0.scopeSpans.0.spans.7.kind": "SPAN_KIND_CLIENT", "batches.0.scopeSpans.0.spans.7.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"url.scheme\").value.stringValue": "http", "batches.0.scopeSpans.0.spans.7.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file",
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"http.response.status_code\").value.intValue": "502", "batches.0.scopeSpans.0.spans.7.attributes.#(key=\"http.request.resend_count\").value.intValue": "1",
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1",
"batches.0.scopeSpans.0.spans.8.name": "Retry", "batches.0.scopeSpans.0.spans.8.name": "ReverseProxy",
"batches.0.scopeSpans.0.spans.8.kind": "SPAN_KIND_INTERNAL", "batches.0.scopeSpans.0.spans.8.kind": "SPAN_KIND_CLIENT",
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file", "batches.0.scopeSpans.0.spans.8.attributes.#(key=\"http.request.method\").value.stringValue": "GET",
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"http.resend_count\").value.intValue": "2", "batches.0.scopeSpans.0.spans.8.attributes.#(key=\"network.protocol.version\").value.stringValue": "1.1",
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"url.full\").value.stringValue": fmt.Sprintf("http://%s/retry", net.JoinHostPort(s.whoamiIP, "81")),
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1",
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"network.peer.address\").value.stringValue": s.whoamiIP,
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"network.peer.port\").value.intValue": "81",
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"server.address\").value.stringValue": s.whoamiIP,
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"server.port\").value.intValue": "81",
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"http.response.status_code\").value.intValue": "502",
"batches.0.scopeSpans.0.spans.8.status.code": "STATUS_CODE_ERROR",
"batches.0.scopeSpans.0.spans.9.name": "Service", "batches.0.scopeSpans.0.spans.9.name": "Metrics",
"batches.0.scopeSpans.0.spans.9.kind": "SPAN_KIND_INTERNAL", "batches.0.scopeSpans.0.spans.9.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.9.attributes.#(key=\"traefik.service.name\").value.stringValue": "service2@file", "batches.0.scopeSpans.0.spans.9.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "metrics-service",
"batches.0.scopeSpans.0.spans.10.name": "ReverseProxy", "batches.0.scopeSpans.0.spans.10.name": "Service",
"batches.0.scopeSpans.0.spans.10.kind": "SPAN_KIND_CLIENT", "batches.0.scopeSpans.0.spans.10.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.10.attributes.#(key=\"url.scheme\").value.stringValue": "http", "batches.0.scopeSpans.0.spans.10.attributes.#(key=\"traefik.service.name\").value.stringValue": "service2@file",
"batches.0.scopeSpans.0.spans.10.attributes.#(key=\"http.response.status_code\").value.intValue": "502",
"batches.0.scopeSpans.0.spans.10.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1", "batches.0.scopeSpans.0.spans.11.name": "Retry",
"batches.0.scopeSpans.0.spans.11.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.11.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file",
"batches.0.scopeSpans.0.spans.11.attributes.#(key=\"http.request.resend_count\").value.intValue": "2",
"batches.0.scopeSpans.0.spans.12.name": "Router",
"batches.0.scopeSpans.0.spans.12.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.12.attributes.#(key=\"traefik.service.name\").value.stringValue": "service2@file",
"batches.0.scopeSpans.0.spans.12.attributes.#(key=\"traefik.router.name\").value.stringValue": "router2@file",
"batches.0.scopeSpans.0.spans.13.name": "Metrics",
"batches.0.scopeSpans.0.spans.13.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.13.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "metrics-entrypoint",
"batches.0.scopeSpans.0.spans.14.name": "EntryPoint",
"batches.0.scopeSpans.0.spans.14.kind": "SPAN_KIND_SERVER",
"batches.0.scopeSpans.0.spans.14.attributes.#(key=\"entry_point\").value.stringValue": "web",
"batches.0.scopeSpans.0.spans.14.attributes.#(key=\"http.request.method\").value.stringValue": "GET",
"batches.0.scopeSpans.0.spans.14.attributes.#(key=\"url.path\").value.stringValue": "/retry",
"batches.0.scopeSpans.0.spans.14.attributes.#(key=\"url.query\").value.stringValue": "",
"batches.0.scopeSpans.0.spans.14.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1",
"batches.0.scopeSpans.0.spans.14.attributes.#(key=\"server.address\").value.stringValue": "127.0.0.1:8000",
"batches.0.scopeSpans.0.spans.14.attributes.#(key=\"network.peer.address\").value.stringValue": "127.0.0.1",
"batches.0.scopeSpans.0.spans.14.attributes.#(key=\"http.response.status_code\").value.intValue": "502",
}, },
} }
@ -393,21 +492,131 @@ func (s *TracingSuite) TestOpentelemetryAuth() {
{ {
"batches.0.scopeSpans.0.scope.name": "github.com/traefik/traefik", "batches.0.scopeSpans.0.scope.name": "github.com/traefik/traefik",
"batches.0.scopeSpans.0.spans.0.name": "EntryPoint", "batches.0.scopeSpans.0.spans.0.name": "BasicAuth",
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.request.method\").value.stringValue": "GET", "batches.0.scopeSpans.0.spans.0.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"url.path\").value.stringValue": "/auth", "batches.0.scopeSpans.0.spans.0.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "basic-auth@file",
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.response.status_code\").value.intValue": "401", "batches.0.scopeSpans.0.spans.0.status.message": "Authentication failed",
"batches.0.scopeSpans.0.spans.0.status.code": "STATUS_CODE_ERROR",
"batches.0.scopeSpans.0.spans.1.name": "Router", "batches.0.scopeSpans.0.spans.1.name": "Retry",
"batches.0.scopeSpans.0.spans.1.kind": "SPAN_KIND_INTERNAL", "batches.0.scopeSpans.0.spans.1.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.router.name\").value.stringValue": "router3@file", "batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file",
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.service.name\").value.stringValue": "service3@file",
"batches.0.scopeSpans.0.spans.2.name": "BasicAuth",
"batches.0.scopeSpans.0.spans.2.kind": "SPAN_KIND_INTERNAL", "batches.0.scopeSpans.0.spans.2.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.2.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file", "batches.0.scopeSpans.0.spans.2.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "basic-auth@file",
"batches.0.scopeSpans.0.spans.2.status.message": "Authentication failed",
"batches.0.scopeSpans.0.spans.2.status.code": "STATUS_CODE_ERROR",
"batches.0.scopeSpans.0.spans.3.name": "Retry",
"batches.0.scopeSpans.0.spans.3.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file",
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"http.request.resend_count\").value.intValue": "1",
"batches.0.scopeSpans.0.spans.4.name": "BasicAuth",
"batches.0.scopeSpans.0.spans.4.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "basic-auth@file",
"batches.0.scopeSpans.0.spans.4.status.message": "Authentication failed",
"batches.0.scopeSpans.0.spans.4.status.code": "STATUS_CODE_ERROR",
"batches.0.scopeSpans.0.spans.5.name": "Retry",
"batches.0.scopeSpans.0.spans.5.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.5.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file",
"batches.0.scopeSpans.0.spans.5.attributes.#(key=\"http.request.resend_count\").value.intValue": "2",
"batches.0.scopeSpans.0.spans.6.name": "Router",
"batches.0.scopeSpans.0.spans.6.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.6.attributes.#(key=\"traefik.service.name\").value.stringValue": "service3@file",
"batches.0.scopeSpans.0.spans.6.attributes.#(key=\"traefik.router.name\").value.stringValue": "router3@file",
"batches.0.scopeSpans.0.spans.6.attributes.#(key=\"http.route\").value.stringValue": "Path(`/auth`)",
"batches.0.scopeSpans.0.spans.7.name": "Metrics",
"batches.0.scopeSpans.0.spans.7.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "metrics-entrypoint",
"batches.0.scopeSpans.0.spans.8.name": "EntryPoint",
"batches.0.scopeSpans.0.spans.8.kind": "SPAN_KIND_SERVER",
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"entry_point\").value.stringValue": "web",
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"http.request.method\").value.stringValue": "GET",
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"url.path\").value.stringValue": "/auth",
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"url.query\").value.stringValue": "",
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1",
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"server.address\").value.stringValue": "127.0.0.1:8000",
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"network.peer.address\").value.stringValue": "127.0.0.1",
"batches.0.scopeSpans.0.spans.8.attributes.#(key=\"http.response.status_code\").value.intValue": "401",
},
}
s.checkTraceContent(contains)
}
func (s *TracingSuite) TestOpentelemetrySafeURL() {
file := s.adaptFile("fixtures/tracing/simple-opentelemetry.toml", TracingTemplate{
WhoamiIP: s.whoamiIP,
WhoamiPort: s.whoamiPort,
IP: s.otelCollectorIP,
})
defer os.Remove(file)
s.traefikCmd(withConfigFile(file))
// wait for traefik
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", time.Second, try.BodyContains("basic-auth"))
require.NoError(s.T(), err)
err = try.GetRequest("http://test:test@127.0.0.1:8000/auth?api_key=powpow", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
require.NoError(s.T(), err)
contains := []map[string]string{
{
"batches.0.scopeSpans.0.scope.name": "github.com/traefik/traefik",
"batches.0.scopeSpans.0.spans.0.name": "ReverseProxy",
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.request.method\").value.stringValue": "GET",
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"url.full\").value.stringValue": fmt.Sprintf("http://REDACTED:REDACTED@%s/auth?api_key=REDACTED", net.JoinHostPort(s.whoamiIP, "80")),
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1",
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"network.peer.address\").value.stringValue": s.whoamiIP,
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"network.peer.port\").value.intValue": "80",
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"server.address\").value.stringValue": s.whoamiIP,
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"server.port\").value.intValue": "80",
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.response.status_code\").value.intValue": "200",
"batches.0.scopeSpans.0.spans.1.name": "Metrics",
"batches.0.scopeSpans.0.spans.1.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "metrics-service",
"batches.0.scopeSpans.0.spans.2.name": "Service",
"batches.0.scopeSpans.0.spans.2.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.2.attributes.#(key=\"traefik.service.name\").value.stringValue": "service3@file",
"batches.0.scopeSpans.0.spans.3.name": "BasicAuth",
"batches.0.scopeSpans.0.spans.3.kind": "SPAN_KIND_INTERNAL", "batches.0.scopeSpans.0.spans.3.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "basic-auth@file", "batches.0.scopeSpans.0.spans.3.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "basic-auth@file",
"batches.0.scopeSpans.0.spans.4.name": "Retry",
"batches.0.scopeSpans.0.spans.4.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file",
"batches.0.scopeSpans.0.spans.5.name": "Router",
"batches.0.scopeSpans.0.spans.5.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.5.attributes.#(key=\"traefik.service.name\").value.stringValue": "service3@file",
"batches.0.scopeSpans.0.spans.5.attributes.#(key=\"traefik.router.name\").value.stringValue": "router3@file",
"batches.0.scopeSpans.0.spans.5.attributes.#(key=\"http.route\").value.stringValue": "Path(`/auth`)",
"batches.0.scopeSpans.0.spans.6.name": "Metrics",
"batches.0.scopeSpans.0.spans.6.kind": "SPAN_KIND_INTERNAL",
"batches.0.scopeSpans.0.spans.6.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "metrics-entrypoint",
"batches.0.scopeSpans.0.spans.7.name": "EntryPoint",
"batches.0.scopeSpans.0.spans.7.kind": "SPAN_KIND_SERVER",
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"entry_point\").value.stringValue": "web",
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"http.request.method\").value.stringValue": "GET",
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"url.path\").value.stringValue": "/auth",
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"url.query\").value.stringValue": "api_key=REDACTED",
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1",
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"server.address\").value.stringValue": "127.0.0.1:8000",
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"network.peer.address\").value.stringValue": "127.0.0.1",
"batches.0.scopeSpans.0.spans.7.attributes.#(key=\"http.response.status_code\").value.intValue": "200",
}, },
} }
@ -517,12 +726,22 @@ func (s *TracingSuite) checkTraceContent(expectedJSON []map[string]string) {
contents = append(contents, string(content)) contents = append(contents, string(content))
} }
var missingElements []string
for _, expected := range expectedJSON { for _, expected := range expectedJSON {
containsAll(expected, contents) missingElements = append(missingElements, contains(expected, contents)...)
} }
log.Printf("Contents: [%s]\n", strings.Join(contents, ","))
for _, element := range missingElements {
log.Printf("Missing elements:\n%s\n", element)
}
require.Empty(s.T(), missingElements)
} }
func containsAll(expectedJSON map[string]string, contents []string) { func contains(expectedJSON map[string]string, contents []string) []string {
var missingElements []string
for k, v := range expectedJSON { for k, v := range expectedJSON {
found := false found := false
for _, content := range contents { for _, content := range contents {
@ -531,12 +750,12 @@ func containsAll(expectedJSON map[string]string, contents []string) {
break break
} }
} }
if !found { if !found {
log.Info().Msgf("[" + strings.Join(contents, ",") + "]") missingElements = append(missingElements, "Key: "+k+", Value: "+v)
log.Error().Msgf("missing element: \nKey: %q\nValue: %q ", k, v)
} }
} }
return missingElements
} }
// TraceResponse contains a list of traces. // TraceResponse contains a list of traces.

View file

@ -201,6 +201,7 @@ type Tracing struct {
GlobalAttributes map[string]string `description:"Defines additional attributes (key:value) on all spans." json:"globalAttributes,omitempty" toml:"globalAttributes,omitempty" yaml:"globalAttributes,omitempty" export:"true"` GlobalAttributes map[string]string `description:"Defines additional attributes (key:value) on all spans." json:"globalAttributes,omitempty" toml:"globalAttributes,omitempty" yaml:"globalAttributes,omitempty" export:"true"`
CapturedRequestHeaders []string `description:"Request headers to add as attributes for server and client spans." json:"capturedRequestHeaders,omitempty" toml:"capturedRequestHeaders,omitempty" yaml:"capturedRequestHeaders,omitempty" export:"true"` CapturedRequestHeaders []string `description:"Request headers to add as attributes for server and client spans." json:"capturedRequestHeaders,omitempty" toml:"capturedRequestHeaders,omitempty" yaml:"capturedRequestHeaders,omitempty" export:"true"`
CapturedResponseHeaders []string `description:"Response headers to add as attributes for server and client spans." json:"capturedResponseHeaders,omitempty" toml:"capturedResponseHeaders,omitempty" yaml:"capturedResponseHeaders,omitempty" export:"true"` CapturedResponseHeaders []string `description:"Response headers to add as attributes for server and client spans." json:"capturedResponseHeaders,omitempty" toml:"capturedResponseHeaders,omitempty" yaml:"capturedResponseHeaders,omitempty" export:"true"`
SafeQueryParams []string `description:"Query params to not redact." json:"safeQueryParams,omitempty" toml:"safeQueryParams,omitempty" yaml:"safeQueryParams,omitempty" export:"true"`
SampleRate float64 `description:"Sets the rate between 0.0 and 1.0 of requests to trace." json:"sampleRate,omitempty" toml:"sampleRate,omitempty" yaml:"sampleRate,omitempty" export:"true"` SampleRate float64 `description:"Sets the rate between 0.0 and 1.0 of requests to trace." json:"sampleRate,omitempty" toml:"sampleRate,omitempty" yaml:"sampleRate,omitempty" export:"true"`
AddInternals bool `description:"Enables tracing for internal services (ping, dashboard, etc...)." json:"addInternals,omitempty" toml:"addInternals,omitempty" yaml:"addInternals,omitempty" export:"true"` AddInternals bool `description:"Enables tracing for internal services (ping, dashboard, etc...)." json:"addInternals,omitempty" toml:"addInternals,omitempty" yaml:"addInternals,omitempty" export:"true"`

View file

@ -20,7 +20,7 @@ import (
"go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/metric"
sdkmetric "go.opentelemetry.io/otel/sdk/metric" sdkmetric "go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/sdk/resource" "go.opentelemetry.io/otel/sdk/resource"
semconv "go.opentelemetry.io/otel/semconv/v1.21.0" semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
"google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials"
"google.golang.org/grpc/encoding/gzip" "google.golang.org/grpc/encoding/gzip"
) )
@ -58,16 +58,16 @@ func NewSemConvMetricRegistry(ctx context.Context, config *types.OTLP) (*SemConv
meter := otel.Meter("github.com/traefik/traefik", meter := otel.Meter("github.com/traefik/traefik",
metric.WithInstrumentationVersion(version.Version)) metric.WithInstrumentationVersion(version.Version))
httpServerRequestDuration, err := meter.Float64Histogram("http.server.request.duration", httpServerRequestDuration, err := meter.Float64Histogram(semconv.HTTPServerRequestDurationName,
metric.WithDescription("Duration of HTTP server requests."), metric.WithDescription(semconv.HTTPServerRequestDurationDescription),
metric.WithUnit("s"), metric.WithUnit("s"),
metric.WithExplicitBucketBoundaries(config.ExplicitBoundaries...)) metric.WithExplicitBucketBoundaries(config.ExplicitBoundaries...))
if err != nil { if err != nil {
return nil, fmt.Errorf("can't build httpServerRequestDuration histogram: %w", err) return nil, fmt.Errorf("can't build httpServerRequestDuration histogram: %w", err)
} }
httpClientRequestDuration, err := meter.Float64Histogram("http.client.request.duration", httpClientRequestDuration, err := meter.Float64Histogram(semconv.HTTPClientRequestDurationName,
metric.WithDescription("Duration of HTTP client requests."), metric.WithDescription(semconv.HTTPClientRequestDurationDescription),
metric.WithUnit("s"), metric.WithUnit("s"),
metric.WithExplicitBucketBoundaries(config.ExplicitBoundaries...)) metric.WithExplicitBucketBoundaries(config.ExplicitBoundaries...))
if err != nil { if err != nil {

View file

@ -513,7 +513,7 @@ func TestForwardAuthTracing(t *testing.T) {
attribute.String("url.scheme", "http"), attribute.String("url.scheme", "http"),
attribute.String("user_agent.original", ""), attribute.String("user_agent.original", ""),
attribute.String("network.peer.address", "127.0.0.1"), attribute.String("network.peer.address", "127.0.0.1"),
attribute.String("network.peer.port", serverPort), attribute.Int64("network.peer.port", int64(serverPortInt)),
attribute.String("server.address", "127.0.0.1"), attribute.String("server.address", "127.0.0.1"),
attribute.Int64("server.port", int64(serverPortInt)), attribute.Int64("server.port", int64(serverPortInt)),
attribute.StringSlice("http.request.header.x-foo", []string{"foo", "bar"}), attribute.StringSlice("http.request.header.x-foo", []string{"foo", "bar"}),
@ -546,7 +546,7 @@ func TestForwardAuthTracing(t *testing.T) {
otel.SetTextMapPropagator(autoprop.NewTextMapPropagator()) otel.SetTextMapPropagator(autoprop.NewTextMapPropagator())
mockTracer := &mockTracer{} mockTracer := &mockTracer{}
tracer := tracing.NewTracer(mockTracer, []string{"X-Foo"}, []string{"X-Bar"}) tracer := tracing.NewTracer(mockTracer, []string{"X-Foo"}, []string{"X-Bar"}, []string{"q"})
initialCtx, initialSpan := tracer.Start(req.Context(), "initial") initialCtx, initialSpan := tracer.Start(req.Context(), "initial")
defer initialSpan.End() defer initialSpan.End()
req = req.WithContext(initialCtx) req = req.WithContext(initialCtx)

View file

@ -14,7 +14,7 @@ import (
"github.com/traefik/traefik/v3/pkg/tracing" "github.com/traefik/traefik/v3/pkg/tracing"
"go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/metric"
semconv "go.opentelemetry.io/otel/semconv/v1.21.0" semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
"go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/trace"
"go.opentelemetry.io/otel/trace/noop" "go.opentelemetry.io/otel/trace/noop"
) )
@ -35,7 +35,7 @@ type entryPointTracing struct {
func WrapEntryPointHandler(ctx context.Context, tracer *tracing.Tracer, semConvMetricRegistry *metrics.SemConvMetricsRegistry, entryPointName string) alice.Constructor { func WrapEntryPointHandler(ctx context.Context, tracer *tracing.Tracer, semConvMetricRegistry *metrics.SemConvMetricsRegistry, entryPointName string) alice.Constructor {
return func(next http.Handler) (http.Handler, error) { return func(next http.Handler) (http.Handler, error) {
if tracer == nil { if tracer == nil {
tracer = tracing.NewTracer(noop.Tracer{}, nil, nil) tracer = tracing.NewTracer(noop.Tracer{}, nil, nil, nil)
} }
return newEntryPoint(ctx, tracer, semConvMetricRegistry, entryPointName, next), nil return newEntryPoint(ctx, tracer, semConvMetricRegistry, entryPointName, next), nil
@ -47,7 +47,7 @@ func newEntryPoint(ctx context.Context, tracer *tracing.Tracer, semConvMetricReg
middlewares.GetLogger(ctx, "tracing", entryPointTypeName).Debug().Msg("Creating middleware") middlewares.GetLogger(ctx, "tracing", entryPointTypeName).Debug().Msg("Creating middleware")
if tracer == nil { if tracer == nil {
tracer = tracing.NewTracer(noop.Tracer{}, nil, nil) tracer = tracing.NewTracer(noop.Tracer{}, nil, nil, nil)
} }
return &entryPointTracing{ return &entryPointTracing{

View file

@ -42,15 +42,14 @@ func TestEntryPointMiddleware_tracing(t *testing.T) {
attribute.String("network.protocol.version", "1.1"), attribute.String("network.protocol.version", "1.1"),
attribute.Int64("http.request.body.size", int64(0)), attribute.Int64("http.request.body.size", int64(0)),
attribute.String("url.path", "/search"), attribute.String("url.path", "/search"),
attribute.String("url.query", "q=Opentelemetry"), attribute.String("url.query", "q=Opentelemetry&token=REDACTED"),
attribute.String("url.scheme", "http"), attribute.String("url.scheme", "http"),
attribute.String("user_agent.original", "entrypoint-test"), attribute.String("user_agent.original", "entrypoint-test"),
attribute.String("server.address", "www.test.com"), attribute.String("server.address", "www.test.com"),
attribute.String("network.peer.address", "10.0.0.1"), attribute.String("network.peer.address", "10.0.0.1"),
attribute.String("network.peer.port", "1234"),
attribute.String("client.address", "10.0.0.1"), attribute.String("client.address", "10.0.0.1"),
attribute.Int64("client.port", int64(1234)), attribute.Int64("client.port", int64(1234)),
attribute.String("client.socket.address", ""), attribute.Int64("network.peer.port", int64(1234)),
attribute.StringSlice("http.request.header.x-foo", []string{"foo", "bar"}), attribute.StringSlice("http.request.header.x-foo", []string{"foo", "bar"}),
attribute.Int64("http.response.status_code", int64(404)), attribute.Int64("http.response.status_code", int64(404)),
attribute.StringSlice("http.response.header.x-bar", []string{"foo", "bar"}), attribute.StringSlice("http.response.header.x-bar", []string{"foo", "bar"}),
@ -61,7 +60,7 @@ func TestEntryPointMiddleware_tracing(t *testing.T) {
for _, test := range testCases { for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) { t.Run(test.desc, func(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "http://www.test.com/search?q=Opentelemetry", nil) req := httptest.NewRequest(http.MethodGet, "http://www.test.com/search?q=Opentelemetry&token=123", nil)
rw := httptest.NewRecorder() rw := httptest.NewRecorder()
req.RemoteAddr = "10.0.0.1:1234" req.RemoteAddr = "10.0.0.1:1234"
req.Header.Set("User-Agent", "entrypoint-test") req.Header.Set("User-Agent", "entrypoint-test")
@ -77,7 +76,7 @@ func TestEntryPointMiddleware_tracing(t *testing.T) {
tracer := &mockTracer{} tracer := &mockTracer{}
handler := newEntryPoint(context.Background(), tracing.NewTracer(tracer, []string{"X-Foo"}, []string{"X-Bar"}), nil, test.entryPoint, next) handler := newEntryPoint(context.Background(), tracing.NewTracer(tracer, []string{"X-Foo"}, []string{"X-Bar"}, []string{"q"}), nil, test.entryPoint, next)
handler.ServeHTTP(rw, req) handler.ServeHTTP(rw, req)
for _, span := range tracer.spans { for _, span := range tracer.spans {

View file

@ -9,7 +9,7 @@ import (
"github.com/traefik/traefik/v3/pkg/middlewares" "github.com/traefik/traefik/v3/pkg/middlewares"
"github.com/traefik/traefik/v3/pkg/tracing" "github.com/traefik/traefik/v3/pkg/tracing"
"go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/attribute"
semconv "go.opentelemetry.io/otel/semconv/v1.21.0" semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
"go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/trace"
) )

View file

@ -16,7 +16,7 @@ import (
"github.com/traefik/traefik/v3/pkg/middlewares" "github.com/traefik/traefik/v3/pkg/middlewares"
"github.com/traefik/traefik/v3/pkg/tracing" "github.com/traefik/traefik/v3/pkg/tracing"
"go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/attribute"
semconv "go.opentelemetry.io/otel/semconv/v1.21.0" semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
"go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/trace"
) )
@ -95,7 +95,7 @@ func (r *retry) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
currentSpan.SetAttributes(attribute.String("traefik.middleware.name", r.name)) currentSpan.SetAttributes(attribute.String("traefik.middleware.name", r.name))
// Only add the attribute "http.resend_count" defined by semantic conventions starting from second attempt. // Only add the attribute "http.resend_count" defined by semantic conventions starting from second attempt.
if attempts > 1 { if attempts > 1 {
currentSpan.SetAttributes(semconv.HTTPResendCount(attempts - 1)) currentSpan.SetAttributes(semconv.HTTPRequestResendCount(attempts - 1))
} }
req = req.WithContext(tracingCtx) req = req.WithContext(tracingCtx)

View file

@ -14,7 +14,7 @@ import (
"github.com/traefik/traefik/v3/pkg/tracing" "github.com/traefik/traefik/v3/pkg/tracing"
"go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/metric"
semconv "go.opentelemetry.io/otel/semconv/v1.21.0" semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
"go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/trace"
) )

View file

@ -18,7 +18,7 @@ import (
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
"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.26.0"
"go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/trace"
"google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials"
"google.golang.org/grpc/encoding/gzip" "google.golang.org/grpc/encoding/gzip"

View file

@ -6,6 +6,8 @@ import (
"io" "io"
"net" "net"
"net/http" "net/http"
"net/url"
"slices"
"strconv" "strconv"
"strings" "strings"
@ -17,7 +19,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/propagation" "go.opentelemetry.io/otel/propagation"
semconv "go.opentelemetry.io/otel/semconv/v1.21.0" semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
"go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/trace"
) )
@ -47,7 +49,7 @@ func NewTracing(conf *static.Tracing) (*Tracer, io.Closer, error) {
return nil, nil, err return nil, nil, err
} }
return NewTracer(tr, conf.CapturedRequestHeaders, conf.CapturedResponseHeaders), closer, nil return NewTracer(tr, conf.CapturedRequestHeaders, conf.CapturedResponseHeaders, conf.SafeQueryParams), closer, nil
} }
// TracerFromContext extracts the trace.Tracer from the given context. // TracerFromContext extracts the trace.Tracer from the given context.
@ -122,14 +124,16 @@ func (t TracerProvider) Tracer(name string, options ...trace.TracerOption) trace
type Tracer struct { type Tracer struct {
trace.Tracer trace.Tracer
safeQueryParams []string
capturedRequestHeaders []string capturedRequestHeaders []string
capturedResponseHeaders []string capturedResponseHeaders []string
} }
// NewTracer builds and configures a new Tracer. // NewTracer builds and configures a new Tracer.
func NewTracer(tracer trace.Tracer, capturedRequestHeaders, capturedResponseHeaders []string) *Tracer { func NewTracer(tracer trace.Tracer, capturedRequestHeaders, capturedResponseHeaders, safeQueryParams []string) *Tracer {
return &Tracer{ return &Tracer{
Tracer: tracer, Tracer: tracer,
safeQueryParams: safeQueryParams,
capturedRequestHeaders: capturedRequestHeaders, capturedRequestHeaders: capturedRequestHeaders,
capturedResponseHeaders: capturedResponseHeaders, capturedResponseHeaders: capturedResponseHeaders,
} }
@ -153,37 +157,37 @@ func (t *Tracer) Start(ctx context.Context, spanName string, opts ...trace.SpanS
} }
// CaptureClientRequest used to add span attributes from the request as a Client. // CaptureClientRequest used to add span attributes from the request as a Client.
// TODO: need to update the semconv package as it does not implement fully Semantic Convention v1.23.0.
func (t *Tracer) CaptureClientRequest(span trace.Span, r *http.Request) { func (t *Tracer) CaptureClientRequest(span trace.Span, r *http.Request) {
if t == nil || span == nil || r == nil { if t == nil || span == nil || r == nil {
return return
} }
// Common attributes https://github.com/open-telemetry/semantic-conventions/blob/v1.23.0/docs/http/http-spans.md#common-attributes // Common attributes https://github.com/open-telemetry/semantic-conventions/blob/v1.26.0/docs/http/http-spans.md#common-attributes
span.SetAttributes(semconv.HTTPRequestMethodKey.String(r.Method)) span.SetAttributes(semconv.HTTPRequestMethodKey.String(r.Method))
span.SetAttributes(semconv.NetworkProtocolVersion(proto(r.Proto))) span.SetAttributes(semconv.NetworkProtocolVersion(proto(r.Proto)))
// Client attributes https://github.com/open-telemetry/semantic-conventions/blob/v1.23.0/docs/http/http-spans.md#http-client // Client attributes https://github.com/open-telemetry/semantic-conventions/blob/v1.26.0/docs/http/http-spans.md#http-client
span.SetAttributes(semconv.URLFull(r.URL.String())) sURL := t.safeURL(r.URL)
span.SetAttributes(semconv.URLScheme(r.URL.Scheme)) span.SetAttributes(semconv.URLFull(sURL.String()))
span.SetAttributes(semconv.URLScheme(sURL.Scheme))
span.SetAttributes(semconv.UserAgentOriginal(r.UserAgent())) span.SetAttributes(semconv.UserAgentOriginal(r.UserAgent()))
host, port, err := net.SplitHostPort(r.URL.Host) host, port, err := net.SplitHostPort(sURL.Host)
if err != nil { if err != nil {
span.SetAttributes(attribute.String("network.peer.address", host)) span.SetAttributes(semconv.NetworkPeerAddress(host))
span.SetAttributes(semconv.ServerAddress(r.URL.Host)) span.SetAttributes(semconv.ServerAddress(sURL.Host))
switch r.URL.Scheme { switch sURL.Scheme {
case "http": case "http":
span.SetAttributes(attribute.String("network.peer.port", "80")) span.SetAttributes(semconv.NetworkPeerPort(80))
span.SetAttributes(semconv.ServerPort(80)) span.SetAttributes(semconv.ServerPort(80))
case "https": case "https":
span.SetAttributes(attribute.String("network.peer.port", "443")) span.SetAttributes(semconv.NetworkPeerPort(443))
span.SetAttributes(semconv.ServerPort(443)) span.SetAttributes(semconv.ServerPort(443))
} }
} else { } else {
span.SetAttributes(attribute.String("network.peer.address", host)) span.SetAttributes(semconv.NetworkPeerAddress(host))
span.SetAttributes(attribute.String("network.peer.port", port))
intPort, _ := strconv.Atoi(port) intPort, _ := strconv.Atoi(port)
span.SetAttributes(semconv.NetworkPeerPort(intPort))
span.SetAttributes(semconv.ServerAddress(host)) span.SetAttributes(semconv.ServerAddress(host))
span.SetAttributes(semconv.ServerPort(intPort)) span.SetAttributes(semconv.ServerPort(intPort))
} }
@ -201,20 +205,20 @@ func (t *Tracer) CaptureClientRequest(span trace.Span, r *http.Request) {
} }
// CaptureServerRequest used to add span attributes from the request as a Server. // CaptureServerRequest used to add span attributes from the request as a Server.
// TODO: need to update the semconv package as it does not implement fully Semantic Convention v1.23.0.
func (t *Tracer) CaptureServerRequest(span trace.Span, r *http.Request) { func (t *Tracer) CaptureServerRequest(span trace.Span, r *http.Request) {
if t == nil || span == nil || r == nil { if t == nil || span == nil || r == nil {
return return
} }
// Common attributes https://github.com/open-telemetry/semantic-conventions/blob/v1.23.0/docs/http/http-spans.md#common-attributes // Common attributes https://github.com/open-telemetry/semantic-conventions/blob/v1.26.0/docs/http/http-spans.md#common-attributes
span.SetAttributes(semconv.HTTPRequestMethodKey.String(r.Method)) span.SetAttributes(semconv.HTTPRequestMethodKey.String(r.Method))
span.SetAttributes(semconv.NetworkProtocolVersion(proto(r.Proto))) span.SetAttributes(semconv.NetworkProtocolVersion(proto(r.Proto)))
// Server attributes https://github.com/open-telemetry/semantic-conventions/blob/v1.23.0/docs/http/http-spans.md#http-server-semantic-conventions sURL := t.safeURL(r.URL)
// Server attributes https://github.com/open-telemetry/semantic-conventions/blob/v1.26.0/docs/http/http-spans.md#http-server-semantic-conventions
span.SetAttributes(semconv.HTTPRequestBodySize(int(r.ContentLength))) span.SetAttributes(semconv.HTTPRequestBodySize(int(r.ContentLength)))
span.SetAttributes(semconv.URLPath(r.URL.Path)) span.SetAttributes(semconv.URLPath(sURL.Path))
span.SetAttributes(semconv.URLQuery(r.URL.RawQuery)) span.SetAttributes(semconv.URLQuery(sURL.RawQuery))
span.SetAttributes(semconv.URLScheme(r.Header.Get("X-Forwarded-Proto"))) span.SetAttributes(semconv.URLScheme(r.Header.Get("X-Forwarded-Proto")))
span.SetAttributes(semconv.UserAgentOriginal(r.UserAgent())) span.SetAttributes(semconv.UserAgentOriginal(r.UserAgent()))
span.SetAttributes(semconv.ServerAddress(r.Host)) span.SetAttributes(semconv.ServerAddress(r.Host))
@ -222,17 +226,15 @@ func (t *Tracer) CaptureServerRequest(span trace.Span, r *http.Request) {
host, port, err := net.SplitHostPort(r.RemoteAddr) host, port, err := net.SplitHostPort(r.RemoteAddr)
if err != nil { if err != nil {
span.SetAttributes(semconv.ClientAddress(r.RemoteAddr)) span.SetAttributes(semconv.ClientAddress(r.RemoteAddr))
span.SetAttributes(attribute.String("network.peer.address", r.RemoteAddr)) span.SetAttributes(semconv.NetworkPeerAddress(r.Host))
} else { } else {
span.SetAttributes(attribute.String("network.peer.address", host)) span.SetAttributes(semconv.NetworkPeerAddress(host))
span.SetAttributes(attribute.String("network.peer.port", port))
span.SetAttributes(semconv.ClientAddress(host)) span.SetAttributes(semconv.ClientAddress(host))
intPort, _ := strconv.Atoi(port) intPort, _ := strconv.Atoi(port)
span.SetAttributes(semconv.ClientPort(intPort)) span.SetAttributes(semconv.ClientPort(intPort))
span.SetAttributes(semconv.NetworkPeerPort(intPort))
} }
span.SetAttributes(semconv.ClientSocketAddress(r.Header.Get("X-Forwarded-For")))
for _, header := range t.capturedRequestHeaders { for _, header := range t.capturedRequestHeaders {
// User-agent is already part of the semantic convention as a recommended attribute. // User-agent is already part of the semantic convention as a recommended attribute.
if strings.EqualFold(header, "User-Agent") { if strings.EqualFold(header, "User-Agent") {
@ -273,6 +275,32 @@ func (t *Tracer) CaptureResponse(span trace.Span, responseHeaders http.Header, c
} }
} }
func (t *Tracer) safeURL(originalURL *url.URL) *url.URL {
if originalURL == nil {
return nil
}
redactedURL := *originalURL
// Redact password if exists.
if redactedURL.User != nil {
redactedURL.User = url.UserPassword("REDACTED", "REDACTED")
}
// Redact query parameters.
query := redactedURL.Query()
for k := range query {
if slices.Contains(t.safeQueryParams, k) {
continue
}
query.Set(k, "REDACTED")
}
redactedURL.RawQuery = query.Encode()
return &redactedURL
}
func proto(proto string) string { func proto(proto string) string {
switch proto { switch proto {
case "HTTP/1.0": case "HTTP/1.0":

View file

@ -0,0 +1,57 @@
package tracing
import (
"net/url"
"testing"
"github.com/stretchr/testify/assert"
)
func Test_safeFullURL(t *testing.T) {
testCases := []struct {
desc string
safeQueryParams []string
originalURL *url.URL
expectedURL *url.URL
}{
{
desc: "Nil URL",
originalURL: nil,
expectedURL: nil,
},
{
desc: "No query parameters",
originalURL: &url.URL{Scheme: "https", Host: "example.com"},
expectedURL: &url.URL{Scheme: "https", Host: "example.com"},
},
{
desc: "All query parameters redacted",
originalURL: &url.URL{Scheme: "https", Host: "example.com", RawQuery: "foo=bar&baz=qux"},
expectedURL: &url.URL{Scheme: "https", Host: "example.com", RawQuery: "baz=REDACTED&foo=REDACTED"},
},
{
desc: "Some query parameters unredacted",
safeQueryParams: []string{"foo"},
originalURL: &url.URL{Scheme: "https", Host: "example.com", RawQuery: "foo=bar&baz=qux"},
expectedURL: &url.URL{Scheme: "https", Host: "example.com", RawQuery: "baz=REDACTED&foo=bar"},
},
{
desc: "User info and some query parameters redacted",
safeQueryParams: []string{"foo"},
originalURL: &url.URL{Scheme: "https", Host: "example.com", User: url.UserPassword("username", "password"), RawQuery: "foo=bar&baz=qux"},
expectedURL: &url.URL{Scheme: "https", Host: "example.com", User: url.UserPassword("REDACTED", "REDACTED"), RawQuery: "baz=REDACTED&foo=bar"},
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
tr := NewTracer(nil, nil, nil, test.safeQueryParams)
gotURL := tr.safeURL(test.originalURL)
assert.Equal(t, test.expectedURL, gotURL)
})
}
}