Merge branch v3.5 into master

This commit is contained in:
kevinpollet 2025-07-24 09:03:26 +02:00
commit 24cede62ee
No known key found for this signature in database
GPG Key ID: 0C9A5DDD1B292453
139 changed files with 1867 additions and 866 deletions

View File

@ -1,17 +1,16 @@
<!-- <!--
PLEASE READ THIS MESSAGE. PLEASE READ THIS MESSAGE.
Documentation fixes or enhancements: Documentation:
- for Traefik v2: use branch v2.11 - for Traefik v2: use branch v2.11 (fixes only)
- for Traefik v3: use branch v3.4 - for Traefik v3: use branch v3.5
Bug fixes: Bug:
- for Traefik v2: use branch v2.11 - for Traefik v2: use branch v2.11 (security fixes only)
- for Traefik v3: use branch v3.4 - for Traefik v3: use branch v3.5
Enhancements: Enhancements:
- for Traefik v2: we only accept bug fixes - use branch master
- for Traefik v3: use branch master
HOW TO WRITE A GOOD PULL REQUEST? https://doc.traefik.io/traefik/contributing/submitting-pull-requests/ HOW TO WRITE A GOOD PULL REQUEST? https://doc.traefik.io/traefik/contributing/submitting-pull-requests/

View File

@ -36,7 +36,21 @@ jobs:
touch webui/static/index.html touch webui/static/index.html
- name: Build binary - name: Build binary
run: make binary run: make binary-linux-amd64
- name: Save go cache build
uses: actions/cache/save@v4
with:
path: |
~/.cache/go-build
key: ${{ runner.os }}-go-build-cache-${{ env.GO_VERSION }}-${{ hashFiles('**/go.sum') }}
- name: Artifact traefik binary
uses: actions/upload-artifact@v4
with:
name: traefik
path: ./dist/linux/amd64/traefik
retention-days: 1
test-integration: test-integration:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -65,8 +79,21 @@ jobs:
mkdir webui/static mkdir webui/static
touch webui/static/index.html touch webui/static/index.html
- name: Build binary - name: Download traefik binary
run: make binary uses: actions/download-artifact@v4
with:
name: traefik
path: ./dist/linux/amd64/
- name: Make binary executable
run: chmod +x ./dist/linux/amd64/traefik
- name: Restore go cache build
uses: actions/cache/restore@v4
with:
path: |
~/.cache/go-build
key: ${{ runner.os }}-go-build-cache-${{ env.GO_VERSION }}-${{ hashFiles('**/go.sum') }}
- name: Generate go test Slice - name: Generate go test Slice
id: test_split id: test_split

View File

@ -1,3 +1,71 @@
## [v3.5.0](https://github.com/traefik/traefik/tree/v3.5.0) (2025-07-23)
[All Commits](https://github.com/traefik/traefik/compare/v3.5.0-rc1...v3.5.0)
**Enhancements:**
- **[acme]** OCSP stapling ([#8393](https://github.com/traefik/traefik/pull/8393) by [alekitto](https://github.com/alekitto))
- **[acme]** Add acme.httpChallenge.delay option ([#11643](https://github.com/traefik/traefik/pull/11643) by [ldez](https://github.com/ldez))
- **[acme]** Allow configuration of ACME provider http timeout ([#11637](https://github.com/traefik/traefik/pull/11637) by [tkw1536](https://github.com/tkw1536))
- **[healthcheck]** Add url option to healthcheck command ([#11711](https://github.com/traefik/traefik/pull/11711) by [Nelwhix](https://github.com/Nelwhix))
- **[healthcheck]** Add unhealthy Interval to the health check configuration ([#10610](https://github.com/traefik/traefik/pull/10610) by [sswastik02](https://github.com/sswastik02))
- **[k8s/gatewayapi]** Bump sigs.k8s.io/gateway-api to v1.3.0 ([#11719](https://github.com/traefik/traefik/pull/11719) by [rtribotte](https://github.com/rtribotte))
- **[k8s/ingress]** Make the behavior of prefix matching in Ingress consistent with Kubernetes doc ([#11203](https://github.com/traefik/traefik/pull/11203) by [charlie0129](https://github.com/charlie0129))
- **[k8s]** NGINX Ingress Provider ([#11844](https://github.com/traefik/traefik/pull/11844) by [rtribotte](https://github.com/rtribotte))
- **[middleware,authentication]** Handle context canceled in ForwardAuth middleware ([#11817](https://github.com/traefik/traefik/pull/11817) by [bengentree](https://github.com/bengentree))
- **[plugins]** Ability to enable unsafe in yaegi through plugin manifest ([#11589](https://github.com/traefik/traefik/pull/11589) by [Rydez](https://github.com/Rydez))
- **[tls]** Introduce X25519MLKEM768 for Post-Quantum-Secure TLS ([#11731](https://github.com/traefik/traefik/pull/11731) by [fzoli](https://github.com/fzoli))
- **[webui]** Migrate Traefik Proxy dashboard UI to React ([#11674](https://github.com/traefik/traefik/pull/11674) by [gndz07](https://github.com/gndz07))
- **[webui]** Improve visualization for StatusRewrites option of errors middleware ([#11806](https://github.com/traefik/traefik/pull/11806) by [sevensolutions](https://github.com/sevensolutions))
**Bug fixes:**
- **[healthcheck]** Revert 11711 adding url param to healthcheck command ([#11927](https://github.com/traefik/traefik/pull/11927) by [lbenguigui](https://github.com/lbenguigui))
- **[logs,metrics,tracing,accesslogs,otel]** Add missing resource attributes detectors ([#11874](https://github.com/traefik/traefik/pull/11874) by [rtribotte](https://github.com/rtribotte))
- **[logs,tracing,k8s,otel]** Add k8s resource attributes automatically ([#11906](https://github.com/traefik/traefik/pull/11906) by [kevinpollet](https://github.com/kevinpollet))
- **[metrics,otel]** Add resourceAttributes option to OTel metrics ([#11908](https://github.com/traefik/traefik/pull/11908) by [kevinpollet](https://github.com/kevinpollet))
- **[middleware,tracing]** Introduce trace verbosity config and produce less spans by default ([#11870](https://github.com/traefik/traefik/pull/11870) by [rtribotte](https://github.com/rtribotte))
**Documentation:**
- **[docker,ecs,docker/swarm,consulcatalog,nomad]** Add constraints key limitations for label providers ([#11893](https://github.com/traefik/traefik/pull/11893) by [bluepuma77](https://github.com/bluepuma77))
- **[k8s]** Add extended NGinX annotation support documentation ([#11920](https://github.com/traefik/traefik/pull/11920) by [nmengin](https://github.com/nmengin))
- Remove dead link to Peka blog ([#11934](https://github.com/traefik/traefik/pull/11934) by [kevinpollet](https://github.com/kevinpollet))
- Prepare release v3.5.0-rc2 ([#11899](https://github.com/traefik/traefik/pull/11899) by [kevinpollet](https://github.com/kevinpollet))
- Prepare release v3.5.0-rc1 ([#11865](https://github.com/traefik/traefik/pull/11865) by [rtribotte](https://github.com/rtribotte))
**Misc:**
- Merge branch v3.4 into v3.5 ([#11933](https://github.com/traefik/traefik/pull/11933) by [rtribotte](https://github.com/rtribotte))
- Merge branch v3.4 into v3.5 ([#11898](https://github.com/traefik/traefik/pull/11898) by [kevinpollet](https://github.com/kevinpollet))
- Merge branch v3.4 into master ([#11863](https://github.com/traefik/traefik/pull/11863) by [rtribotte](https://github.com/rtribotte))
- Merge branch v3.4 into master ([#11861](https://github.com/traefik/traefik/pull/11861) by [rtribotte](https://github.com/rtribotte))
- Merge branch v3.4 into master ([#11857](https://github.com/traefik/traefik/pull/11857) by [rtribotte](https://github.com/rtribotte))
- Merge branch v3.4 into master ([#11855](https://github.com/traefik/traefik/pull/11855) by [rtribotte](https://github.com/rtribotte))
- Merge branch v3.4 into master ([#11813](https://github.com/traefik/traefik/pull/11813) by [kevinpollet](https://github.com/kevinpollet))
- Merge branch v3.4 into master ([#11758](https://github.com/traefik/traefik/pull/11758) by [mmatur](https://github.com/mmatur))
- Merge v3.4 into master ([#11752](https://github.com/traefik/traefik/pull/11752) by [mmatur](https://github.com/mmatur))
- Merge branch v3.4 into master ([#11708](https://github.com/traefik/traefik/pull/11708) by [kevinpollet](https://github.com/kevinpollet))
## [v3.4.5](https://github.com/traefik/traefik/tree/v3.4.5) (2025-07-23)
[All Commits](https://github.com/traefik/traefik/compare/v3.4.4...v3.4.5)
**Bug fixes:**
- **[http3]** Bump github.com/quic-go/quic-go to v0.54.0 ([#11919](https://github.com/traefik/traefik/pull/11919) by [GreyXor](https://github.com/GreyXor))
**Documentation:**
- Fix typo in entrypoints page ([#11914](https://github.com/traefik/traefik/pull/11914) by [adk-swisstopo](https://github.com/adk-swisstopo))
**Misc:**
- Merge branch v2.11 into v3.4 ([#11930](https://github.com/traefik/traefik/pull/11930) by [kevinpollet](https://github.com/kevinpollet))
- Merge branch v2.11 into v3.4 ([#11926](https://github.com/traefik/traefik/pull/11926) by [rtribotte](https://github.com/rtribotte))
## [v2.11.28](https://github.com/traefik/traefik/tree/v2.11.28) (2025-07-23)
[All Commits](https://github.com/traefik/traefik/compare/v2.11.27...v2.11.28)
**Bug fixes:**
- **[logs]** Redact logged install configuration ([#11907](https://github.com/traefik/traefik/pull/11907) by [jspdown](https://github.com/jspdown))
- **[plugins]** Fix client arbitrary file access during archive extraction zipslip ([#11911](https://github.com/traefik/traefik/pull/11911) by [odaysec](https://github.com/odaysec))
- **[server]** Disable MPTCP by default ([#11918](https://github.com/traefik/traefik/pull/11918) by [rtribotte](https://github.com/rtribotte))
**Documentation:**
- **[k8s/crd,k8s]** Remove all mentions of ordering for TLSOption CurvePreferences field ([#11924](https://github.com/traefik/traefik/pull/11924) by [jnoordsij](https://github.com/jnoordsij))
## [v3.5.0-rc2](https://github.com/traefik/traefik/tree/v3.5.0-rc2) (2025-07-11) ## [v3.5.0-rc2](https://github.com/traefik/traefik/tree/v3.5.0-rc2) (2025-07-11)
[All Commits](https://github.com/traefik/traefik/compare/v3.5.0-rc1...v3.5.0-rc2) [All Commits](https://github.com/traefik/traefik/compare/v3.5.0-rc1...v3.5.0-rc2)

View File

@ -93,7 +93,7 @@ test-unit:
.PHONY: test-integration .PHONY: test-integration
#? test-integration: Run the integration tests #? test-integration: Run the integration tests
test-integration: binary test-integration:
GOOS=$(GOOS) GOARCH=$(GOARCH) go test ./integration -test.timeout=20m -failfast -v $(TESTFLAGS) GOOS=$(GOOS) GOARCH=$(GOARCH) go test ./integration -test.timeout=20m -failfast -v $(TESTFLAGS)
.PHONY: test-gateway-api-conformance .PHONY: test-gateway-api-conformance

View File

@ -152,7 +152,7 @@ We use [Semantic Versioning](https://semver.org/).
## Credits ## Credits
Kudos to [Peka](http://peka.byethost11.com/photoblog/) for his awesome work on the gopher's logo!. Kudos to Peka for his awesome work on the gopher's logo!.
The gopher's logo of Traefik is licensed under the Creative Commons 3.0 Attributions license. The gopher's logo of Traefik is licensed under the Creative Commons 3.0 Attributions license.

View File

@ -2,7 +2,6 @@ package healthcheck
import ( import (
"errors" "errors"
"flag"
"fmt" "fmt"
"net/http" "net/http"
"os" "os"
@ -23,26 +22,11 @@ func NewCmd(traefikConfiguration *static.Configuration, loaders []cli.ResourceLo
} }
} }
func runCmd(traefikConfiguration *static.Configuration) func(args []string) error { func runCmd(traefikConfiguration *static.Configuration) func(_ []string) error {
return func(args []string) error { return func(_ []string) error {
fs := flag.NewFlagSet("healthcheck", flag.ContinueOnError)
urlFlag := fs.String("url", "", "")
fs.SetOutput(os.Stderr)
if err := fs.Parse(args); err != nil {
return err
}
traefikConfiguration.SetEffectiveConfiguration() traefikConfiguration.SetEffectiveConfiguration()
var resp *http.Response resp, errPing := Do(*traefikConfiguration)
var errPing error
if *urlFlag != "" {
client := &http.Client{Timeout: 5 * time.Second}
resp, errPing = client.Head(*urlFlag)
} else {
resp, errPing = Do(*traefikConfiguration)
}
if resp != nil { if resp != nil {
resp.Body.Close() resp.Body.Close()
} }

View File

@ -1,6 +1,7 @@
package main package main
import ( import (
"context"
"errors" "errors"
"fmt" "fmt"
"io" "io"
@ -22,7 +23,7 @@ func init() {
zerolog.SetGlobalLevel(zerolog.ErrorLevel) zerolog.SetGlobalLevel(zerolog.ErrorLevel)
} }
func setupLogger(staticConfiguration *static.Configuration) error { func setupLogger(ctx context.Context, staticConfiguration *static.Configuration) error {
// Validate that the experimental flag is set up at this point, // Validate that the experimental flag is set up at this point,
// rather than validating the static configuration before the setupLogger call. // rather than validating the static configuration before the setupLogger call.
// This ensures that validation messages are not logged using an un-configured logger. // This ensures that validation messages are not logged using an un-configured logger.
@ -39,16 +40,16 @@ func setupLogger(staticConfiguration *static.Configuration) error {
zerolog.SetGlobalLevel(logLevel) zerolog.SetGlobalLevel(logLevel)
// create logger // create logger
logCtx := zerolog.New(w).With().Timestamp() logger := zerolog.New(w).With().Timestamp()
if logLevel <= zerolog.DebugLevel { if logLevel <= zerolog.DebugLevel {
logCtx = logCtx.Caller() logger = logger.Caller()
} }
log.Logger = logCtx.Logger().Level(logLevel) log.Logger = logger.Logger().Level(logLevel)
if staticConfiguration.Log != nil && staticConfiguration.Log.OTLP != nil { if staticConfiguration.Log != nil && staticConfiguration.Log.OTLP != nil {
var err error var err error
log.Logger, err = logs.SetupOTelLogger(log.Logger, staticConfiguration.Log.OTLP) log.Logger, err = logs.SetupOTelLogger(ctx, log.Logger, staticConfiguration.Log.OTLP)
if err != nil { if err != nil {
return fmt.Errorf("setting up OpenTelemetry logger: %w", err) return fmt.Errorf("setting up OpenTelemetry logger: %w", err)
} }

View File

@ -3,7 +3,6 @@ package main
import ( import (
"context" "context"
"crypto/x509" "crypto/x509"
"encoding/json"
"fmt" "fmt"
"io" "io"
stdlog "log" stdlog "log"
@ -40,6 +39,7 @@ import (
"github.com/traefik/traefik/v3/pkg/provider/traefik" "github.com/traefik/traefik/v3/pkg/provider/traefik"
"github.com/traefik/traefik/v3/pkg/proxy" "github.com/traefik/traefik/v3/pkg/proxy"
"github.com/traefik/traefik/v3/pkg/proxy/httputil" "github.com/traefik/traefik/v3/pkg/proxy/httputil"
"github.com/traefik/traefik/v3/pkg/redactor"
"github.com/traefik/traefik/v3/pkg/safe" "github.com/traefik/traefik/v3/pkg/safe"
"github.com/traefik/traefik/v3/pkg/server" "github.com/traefik/traefik/v3/pkg/server"
"github.com/traefik/traefik/v3/pkg/server/middleware" "github.com/traefik/traefik/v3/pkg/server/middleware"
@ -90,7 +90,10 @@ Complete documentation is available at https://traefik.io`,
} }
func runCmd(staticConfiguration *static.Configuration) error { func runCmd(staticConfiguration *static.Configuration) error {
if err := setupLogger(staticConfiguration); err != nil { ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
defer cancel()
if err := setupLogger(ctx, staticConfiguration); err != nil {
return fmt.Errorf("setting up logger: %w", err) return fmt.Errorf("setting up logger: %w", err)
} }
@ -104,12 +107,11 @@ func runCmd(staticConfiguration *static.Configuration) error {
log.Info().Str("version", version.Version). log.Info().Str("version", version.Version).
Msgf("Traefik version %s built on %s", version.Version, version.BuildDate) Msgf("Traefik version %s built on %s", version.Version, version.BuildDate)
jsonConf, err := json.Marshal(staticConfiguration) redactedStaticConfiguration, err := redactor.RemoveCredentials(staticConfiguration)
if err != nil { if err != nil {
log.Error().Err(err).Msg("Could not marshal static configuration") log.Error().Err(err).Msg("Could not redact static configuration")
log.Debug().Interface("staticConfiguration", staticConfiguration).Msg("Static configuration loaded [struct]")
} else { } else {
log.Debug().RawJSON("staticConfiguration", jsonConf).Msg("Static configuration loaded [json]") log.Debug().RawJSON("staticConfiguration", []byte(redactedStaticConfiguration)).Msg("Static configuration loaded [json]")
} }
if staticConfiguration.Global.CheckNewVersion { if staticConfiguration.Global.CheckNewVersion {
@ -123,8 +125,6 @@ func runCmd(staticConfiguration *static.Configuration) error {
return err return err
} }
ctx, _ := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
if staticConfiguration.Ping != nil { if staticConfiguration.Ping != nil {
staticConfiguration.Ping.WithContext(ctx) staticConfiguration.Ping.WithContext(ctx)
} }
@ -210,8 +210,8 @@ func setupServer(staticConfiguration *static.Configuration) (*server.Server, err
} }
} }
metricsRegistry := metrics.NewMultiRegistry(metricRegistries) metricsRegistry := metrics.NewMultiRegistry(metricRegistries)
accessLog := setupAccessLog(staticConfiguration.AccessLog) accessLog := setupAccessLog(ctx, staticConfiguration.AccessLog)
tracer, tracerCloser := setupTracing(staticConfiguration.Tracing) tracer, tracerCloser := setupTracing(ctx, staticConfiguration.Tracing)
observabilityMgr := middleware.NewObservabilityMgr(*staticConfiguration, metricsRegistry, semConvMetricRegistry, accessLog, tracer, tracerCloser) observabilityMgr := middleware.NewObservabilityMgr(*staticConfiguration, metricsRegistry, semConvMetricRegistry, accessLog, tracer, tracerCloser)
// Entrypoints // Entrypoints
@ -586,12 +586,12 @@ func appendCertMetric(gauge gokitmetrics.Gauge, certificate *x509.Certificate) {
gauge.With(labels...).Set(notAfter) gauge.With(labels...).Set(notAfter)
} }
func setupAccessLog(conf *types.AccessLog) *accesslog.Handler { func setupAccessLog(ctx context.Context, conf *types.AccessLog) *accesslog.Handler {
if conf == nil { if conf == nil {
return nil return nil
} }
accessLoggerMiddleware, err := accesslog.NewHandler(conf) accessLoggerMiddleware, err := accesslog.NewHandler(ctx, conf)
if err != nil { if err != nil {
log.Warn().Err(err).Msg("Unable to create access logger") log.Warn().Err(err).Msg("Unable to create access logger")
return nil return nil
@ -600,12 +600,12 @@ func setupAccessLog(conf *types.AccessLog) *accesslog.Handler {
return accessLoggerMiddleware return accessLoggerMiddleware
} }
func setupTracing(conf *static.Tracing) (*tracing.Tracer, io.Closer) { func setupTracing(ctx context.Context, conf *static.Tracing) (*tracing.Tracer, io.Closer) {
if conf == nil { if conf == nil {
return nil, nil return nil, nil
} }
tracer, closer, err := tracing.NewTracing(conf) tracer, closer, err := tracing.NewTracing(ctx, conf)
if err != nil { if err != nil {
log.Warn().Err(err).Msg("Unable to create tracer") log.Warn().Err(err).Msg("Unable to create tracer")
return nil, nil return nil, nil

View File

@ -384,11 +384,11 @@ spec:
### Curve Preferences ### Curve Preferences
This option allows to set the preferred elliptic curves in a specific order. This option allows to set the enabled elliptic curves for key exchange.
The names of the curves defined by [`crypto`](https://godoc.org/crypto/tls#CurveID) (e.g. `CurveP521`) and the [RFC defined names](https://tools.ietf.org/html/rfc8446#section-4.2.7) (e. g. `secp521r1`) can be used. The names of the curves defined by [`crypto`](https://godoc.org/crypto/tls#CurveID) (e.g. `CurveP521`) and the [RFC defined names](https://tools.ietf.org/html/rfc8446#section-4.2.7) (e. g. `secp521r1`) can be used.
See [CurveID](https://godoc.org/crypto/tls#CurveID) for more information. See [CurvePreferences](https://godoc.org/crypto/tls#Config.CurvePreferences) and [CurveID](https://godoc.org/crypto/tls#CurveID) for more information.
```yaml tab="File (YAML)" ```yaml tab="File (YAML)"
# Dynamic configuration # Dynamic configuration

View File

@ -706,3 +706,14 @@ and Traefik now keeps them encoded to avoid any ambiguity.
| `/foo/../bar` | PathPrefix(`/bar`) | Match | Match | | `/foo/../bar` | PathPrefix(`/bar`) | Match | Match |
| `/foo/%2E%2E/bar` | PathPrefix(`/foo`) | Match | No match | | `/foo/%2E%2E/bar` | PathPrefix(`/foo`) | Match | No match |
| `/foo/%2E%2E/bar` | PathPrefix(`/bar`) | No match | Match | | `/foo/%2E%2E/bar` | PathPrefix(`/bar`) | No match | Match |
## v2.11.28
### MultiPath TCP
Since `v2.11.28`, the MultiPath TCP support introduced with `v2.11.26` has been removed.
It appears that enabling MPTCP on some platforms can cause Traefik to stop with the following error logs message:
- `set tcp X.X.X.X:X->X.X.X.X:X: setsockopt: operation not supported`
However, it can be re-enabled by setting the `multipathtcp` variable in the GODEBUG environment variable, see the related [go documentation](https://go.dev/doc/godebug#go-124).

View File

@ -319,3 +319,53 @@ and Traefik now keeps them encoded to avoid any ambiguity.
| `/foo/../bar` | PathPrefix(`/bar`) | Match | Match | | `/foo/../bar` | PathPrefix(`/bar`) | Match | Match |
| `/foo/%2E%2E/bar` | PathPrefix(`/foo`) | Match | No match | | `/foo/%2E%2E/bar` | PathPrefix(`/foo`) | Match | No match |
| `/foo/%2E%2E/bar` | PathPrefix(`/bar`) | No match | Match | | `/foo/%2E%2E/bar` | PathPrefix(`/bar`) | No match | Match |
## v3.4.5
### MultiPath TCP
Since `v3.4.5`, the MultiPath TCP support introduced with `v3.4.2` has been removed.
It appears that enabling MPTCP on some platforms can cause Traefik to stop with the following error logs message:
- `set tcp X.X.X.X:X->X.X.X.X:X: setsockopt: operation not supported`
However, it can be re-enabled by setting the `multipathtcp` variable in the GODEBUG environment variable, see the related [go documentation](https://go.dev/doc/godebug#go-124).
## v3.5.0
### Observability
#### TraceVerbosity on Routers and Entrypoints
Starting with `v3.5.0`, a new `traceVerbosity` option is available for both entrypoints and routers.
This option allows you to control the level of detail for tracing spans.
Routers can override the value inherited from their entrypoint.
**Impact:**
- If you rely on tracing, review your configuration to explicitly set the desired verbosity level.
- Existing configurations will default to `minimal` unless overridden, which will result in fewer spans being generated than before.
Possible values are:
- `minimal`: produces a single server span and one client span for each request processed by a router.
- `detailed`: enables the creation of additional spans for each middleware executed for each request processed by a router.
See the updated documentation for [entrypoints](../reference/install-configuration/entrypoints.md) and [dynamic routers](../reference/dynamic-configuration/file.md#observability-options).
#### K8s Resource Attributes
Since `v3.5.0`, the semconv attributes `k8s.pod.name` and `k8s.pod.uid` are injected automatically in OTel resource attributes when OTel tracing/logs/metrics are enabled.
For that purpose, the following right has to be added to the Traefik Kubernetes RBACs:
```yaml
...
- apiGroups:
- ""
resources:
- pods
verbs:
- get
...
```

View File

@ -340,6 +340,54 @@ accesslog:
The OpenTelemetry Logger exporter will export access logs to the collector using HTTPS by default to https://localhost:4318/v1/logs, see the [gRPC Section](#grpc-configuration) to use gRPC. The OpenTelemetry Logger exporter will export access logs to the collector using HTTPS by default to https://localhost:4318/v1/logs, see the [gRPC Section](#grpc-configuration) to use gRPC.
### `serviceName`
_Optional, Default="traefik"_
Defines the service name resource attribute.
```yaml tab="File (YAML)"
accesslog:
otlp:
serviceName: name
```
```toml tab="File (TOML)"
[accesslog]
[accesslog.otlp]
serviceName = "name"
```
```bash tab="CLI"
--accesslog.otlp.serviceName=name
```
### `ressourceAttributes`
_Optional, Default=empty_
Defines additional resource attributes to be sent to the collector.
```yaml tab="File (YAML)"
accesslog:
otlp:
resourceAttributes:
attr1: foo
attr2: bar
```
```toml tab="File (TOML)"
[accesslog]
[accesslog.otlp.resourceAttributes]
attr1 = "foo"
attr2 = "bar"
```
```bash tab="CLI"
--accesslog.otlp.resourceAttributes.attr1=foo
--accesslog.otlp.resourceAttributes.attr2=bar
```
### HTTP configuration ### HTTP configuration
_Optional_ _Optional_

View File

@ -219,6 +219,54 @@ log:
The OpenTelemetry Logger exporter will export logs to the collector using HTTPS by default to https://localhost:4318/v1/logs, see the [gRPC Section](#grpc-configuration) to use gRPC. The OpenTelemetry Logger exporter will export logs to the collector using HTTPS by default to https://localhost:4318/v1/logs, see the [gRPC Section](#grpc-configuration) to use gRPC.
### `serviceName`
_Optional, Default="traefik"_
Defines the service name resource attribute.
```yaml tab="File (YAML)"
log:
otlp:
serviceName: name
```
```toml tab="File (TOML)"
[log]
[log.otlp]
serviceName = "name"
```
```bash tab="CLI"
--log.otlp.serviceName=name
```
### `ressourceAttributes`
_Optional, Default=empty_
Defines additional resource attributes to be sent to the collector.
```yaml tab="File (YAML)"
log:
otlp:
resourceAttributes:
attr1: foo
attr2: bar
```
```toml tab="File (TOML)"
[log]
[log.otlp.resourceAttributes]
attr1 = "foo"
attr2 = "bar"
```
```bash tab="CLI"
--log.otlp.resourceAttributes.attr1=foo
--log.otlp.resourceAttributes.attr2=bar
```
### HTTP configuration ### HTTP configuration
_Optional_ _Optional_

View File

@ -143,7 +143,7 @@ metrics:
_Optional, Default="traefik"_ _Optional, Default="traefik"_
OTEL service name to use. Defines the service name resource attribute.
```yaml tab="File (YAML)" ```yaml tab="File (YAML)"
metrics: metrics:
@ -160,6 +160,31 @@ metrics:
```bash tab="CLI" ```bash tab="CLI"
--metrics.otlp.serviceName=name --metrics.otlp.serviceName=name
``` ```
#### `ressourceAttributes`
_Optional, Default=empty_
Defines additional resource attributes to be sent to the collector.
```yaml tab="File (YAML)"
metrics:
otlp:
resourceAttributes:
attr1: foo
attr2: bar
```
```toml tab="File (TOML)"
[metrics]
[metrics.otlp.resourceAttributes]
attr1 = "foo"
attr2 = "bar"
```
```bash tab="CLI"
--metrics.otlp.resourceAttributes.attr1=foo
--metrics.otlp.resourceAttributes.attr2=bar
```
### HTTP configuration ### HTTP configuration

View File

@ -169,6 +169,7 @@
- "traefik.http.routers.router0.middlewares=foobar, foobar" - "traefik.http.routers.router0.middlewares=foobar, foobar"
- "traefik.http.routers.router0.observability.accesslogs=true" - "traefik.http.routers.router0.observability.accesslogs=true"
- "traefik.http.routers.router0.observability.metrics=true" - "traefik.http.routers.router0.observability.metrics=true"
- "traefik.http.routers.router0.observability.traceverbosity=foobar"
- "traefik.http.routers.router0.observability.tracing=true" - "traefik.http.routers.router0.observability.tracing=true"
- "traefik.http.routers.router0.priority=42" - "traefik.http.routers.router0.priority=42"
- "traefik.http.routers.router0.rule=foobar" - "traefik.http.routers.router0.rule=foobar"
@ -185,6 +186,7 @@
- "traefik.http.routers.router1.middlewares=foobar, foobar" - "traefik.http.routers.router1.middlewares=foobar, foobar"
- "traefik.http.routers.router1.observability.accesslogs=true" - "traefik.http.routers.router1.observability.accesslogs=true"
- "traefik.http.routers.router1.observability.metrics=true" - "traefik.http.routers.router1.observability.metrics=true"
- "traefik.http.routers.router1.observability.traceverbosity=foobar"
- "traefik.http.routers.router1.observability.tracing=true" - "traefik.http.routers.router1.observability.tracing=true"
- "traefik.http.routers.router1.priority=42" - "traefik.http.routers.router1.priority=42"
- "traefik.http.routers.router1.rule=foobar" - "traefik.http.routers.router1.rule=foobar"

View File

@ -22,8 +22,9 @@
sans = ["foobar", "foobar"] sans = ["foobar", "foobar"]
[http.routers.Router0.observability] [http.routers.Router0.observability]
accessLogs = true accessLogs = true
tracing = true
metrics = true metrics = true
tracing = true
traceVerbosity = "foobar"
[http.routers.Router1] [http.routers.Router1]
entryPoints = ["foobar", "foobar"] entryPoints = ["foobar", "foobar"]
middlewares = ["foobar", "foobar"] middlewares = ["foobar", "foobar"]
@ -44,8 +45,9 @@
sans = ["foobar", "foobar"] sans = ["foobar", "foobar"]
[http.routers.Router1.observability] [http.routers.Router1.observability]
accessLogs = true accessLogs = true
tracing = true
metrics = true metrics = true
tracing = true
traceVerbosity = "foobar"
[http.services] [http.services]
[http.services.Service01] [http.services.Service01]
[http.services.Service01.failover] [http.services.Service01.failover]

View File

@ -27,8 +27,9 @@ http:
- foobar - foobar
observability: observability:
accessLogs: true accessLogs: true
tracing: true
metrics: true metrics: true
tracing: true
traceVerbosity: foobar
Router1: Router1:
entryPoints: entryPoints:
- foobar - foobar
@ -54,8 +55,9 @@ http:
- foobar - foobar
observability: observability:
accessLogs: true accessLogs: true
tracing: true
metrics: true metrics: true
tracing: true
traceVerbosity: foobar
services: services:
Service01: Service01:
failover: failover:

View File

@ -92,10 +92,21 @@ spec:
More info: https://doc.traefik.io/traefik/v3.5/routing/routers/#observability More info: https://doc.traefik.io/traefik/v3.5/routing/routers/#observability
properties: properties:
accessLogs: accessLogs:
description: AccessLogs enables access logs for this router.
type: boolean type: boolean
metrics: metrics:
description: Metrics enables metrics for this router.
type: boolean type: boolean
traceVerbosity:
default: minimal
description: TraceVerbosity defines the verbosity level
of the tracing for this router.
enum:
- minimal
- detailed
type: string
tracing: tracing:
description: Tracing enables tracing for this router.
type: boolean type: boolean
type: object type: object
priority: priority:
@ -2551,7 +2562,7 @@ spec:
type: object type: object
curvePreferences: curvePreferences:
description: |- description: |-
CurvePreferences defines the preferred elliptic curves in a specific order. CurvePreferences defines the preferred elliptic curves.
More info: https://doc.traefik.io/traefik/v3.5/https/tls/#curve-preferences More info: https://doc.traefik.io/traefik/v3.5/https/tls/#curve-preferences
items: items:
type: string type: string

View File

@ -15,6 +15,14 @@ rules:
- get - get
- list - list
- watch - watch
# The pods right is needed to inject k8s.pod.uid and k8s.pod.name OTel attributes.
# When OTel tracing/logs/metrics are not enabled, this rule is not needed.
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- apiGroups: - apiGroups:
- discovery.k8s.io - discovery.k8s.io
resources: resources:

View File

@ -11,6 +11,14 @@ rules:
verbs: verbs:
- list - list
- watch - watch
# The pods get right is needed to inject k8s.pod.uid and k8s.pod.name in OTel attributes.
# When OTel tracing/logs/metrics are not enabled, this rule is not needed.
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- apiGroups: - apiGroups:
- "" - ""
resources: resources:

View File

@ -199,6 +199,7 @@ THIS FILE MUST NOT BE EDITED BY HAND
| `traefik/http/routers/Router0/middlewares/1` | `foobar` | | `traefik/http/routers/Router0/middlewares/1` | `foobar` |
| `traefik/http/routers/Router0/observability/accessLogs` | `true` | | `traefik/http/routers/Router0/observability/accessLogs` | `true` |
| `traefik/http/routers/Router0/observability/metrics` | `true` | | `traefik/http/routers/Router0/observability/metrics` | `true` |
| `traefik/http/routers/Router0/observability/traceVerbosity` | `foobar` |
| `traefik/http/routers/Router0/observability/tracing` | `true` | | `traefik/http/routers/Router0/observability/tracing` | `true` |
| `traefik/http/routers/Router0/priority` | `42` | | `traefik/http/routers/Router0/priority` | `42` |
| `traefik/http/routers/Router0/rule` | `foobar` | | `traefik/http/routers/Router0/rule` | `foobar` |
@ -218,6 +219,7 @@ THIS FILE MUST NOT BE EDITED BY HAND
| `traefik/http/routers/Router1/middlewares/1` | `foobar` | | `traefik/http/routers/Router1/middlewares/1` | `foobar` |
| `traefik/http/routers/Router1/observability/accessLogs` | `true` | | `traefik/http/routers/Router1/observability/accessLogs` | `true` |
| `traefik/http/routers/Router1/observability/metrics` | `true` | | `traefik/http/routers/Router1/observability/metrics` | `true` |
| `traefik/http/routers/Router1/observability/traceVerbosity` | `foobar` |
| `traefik/http/routers/Router1/observability/tracing` | `true` | | `traefik/http/routers/Router1/observability/tracing` | `true` |
| `traefik/http/routers/Router1/priority` | `42` | | `traefik/http/routers/Router1/priority` | `42` |
| `traefik/http/routers/Router1/rule` | `foobar` | | `traefik/http/routers/Router1/rule` | `foobar` |

View File

@ -0,0 +1,114 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.16.1
name: tlsoptions.traefik.containo.us
spec:
group: traefik.containo.us
names:
kind: TLSOption
listKind: TLSOptionList
plural: tlsoptions
singular: tlsoption
scope: Namespaced
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
description: |-
TLSOption is the CRD implementation of a Traefik TLS Option, allowing to configure some parameters of the TLS connection.
More info: https://doc.traefik.io/traefik/v2.11/https/tls/#tls-options
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string
metadata:
type: object
spec:
description: TLSOptionSpec defines the desired state of a TLSOption.
properties:
alpnProtocols:
description: |-
ALPNProtocols defines the list of supported application level protocols for the TLS handshake, in order of preference.
More info: https://doc.traefik.io/traefik/v2.11/https/tls/#alpn-protocols
items:
type: string
type: array
cipherSuites:
description: |-
CipherSuites defines the list of supported cipher suites for TLS versions up to TLS 1.2.
More info: https://doc.traefik.io/traefik/v2.11/https/tls/#cipher-suites
items:
type: string
type: array
clientAuth:
description: ClientAuth defines the server's policy for TLS Client
Authentication.
properties:
clientAuthType:
description: ClientAuthType defines the client authentication
type to apply.
enum:
- NoClientCert
- RequestClientCert
- RequireAnyClientCert
- VerifyClientCertIfGiven
- RequireAndVerifyClientCert
type: string
secretNames:
description: SecretNames defines the names of the referenced Kubernetes
Secret storing certificate details.
items:
type: string
type: array
type: object
curvePreferences:
description: |-
CurvePreferences defines the preferred elliptic curves.
More info: https://doc.traefik.io/traefik/v2.11/https/tls/#curve-preferences
items:
type: string
type: array
maxVersion:
description: |-
MaxVersion defines the maximum TLS version that Traefik will accept.
Possible values: VersionTLS10, VersionTLS11, VersionTLS12, VersionTLS13.
Default: None.
type: string
minVersion:
description: |-
MinVersion defines the minimum TLS version that Traefik will accept.
Possible values: VersionTLS10, VersionTLS11, VersionTLS12, VersionTLS13.
Default: VersionTLS10.
type: string
preferServerCipherSuites:
description: |-
PreferServerCipherSuites defines whether the server chooses a cipher suite among his own instead of among the client's.
It is enabled automatically when minVersion or maxVersion is set.
Deprecated: https://github.com/golang/go/issues/45430
type: boolean
sniStrict:
description: SniStrict defines whether Traefik allows connections
from clients connections that do not specify a server_name extension.
type: boolean
type: object
required:
- metadata
- spec
type: object
served: true
storage: true

View File

@ -92,10 +92,21 @@ spec:
More info: https://doc.traefik.io/traefik/v3.5/routing/routers/#observability More info: https://doc.traefik.io/traefik/v3.5/routing/routers/#observability
properties: properties:
accessLogs: accessLogs:
description: AccessLogs enables access logs for this router.
type: boolean type: boolean
metrics: metrics:
description: Metrics enables metrics for this router.
type: boolean type: boolean
traceVerbosity:
default: minimal
description: TraceVerbosity defines the verbosity level
of the tracing for this router.
enum:
- minimal
- detailed
type: string
tracing: tracing:
description: Tracing enables tracing for this router.
type: boolean type: boolean
type: object type: object
priority: priority:

View File

@ -78,7 +78,7 @@ spec:
type: object type: object
curvePreferences: curvePreferences:
description: |- description: |-
CurvePreferences defines the preferred elliptic curves in a specific order. CurvePreferences defines the preferred elliptic curves.
More info: https://doc.traefik.io/traefik/v3.5/https/tls/#curve-preferences More info: https://doc.traefik.io/traefik/v3.5/https/tls/#curve-preferences
items: items:
type: string type: string

View File

@ -84,7 +84,7 @@ additionalArguments:
## Configuration Options ## Configuration Options
| Field | Description | Default | Required | | Field | Description | Default | Required |
|:-----------------|:--------|:--------|:---------| |:----------------------------------------------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:------------------------|:---------|
| `address` | Define the port, and optionally the hostname, on which to listen for incoming connections and packets.<br /> It also defines the protocol to use (TCP or UDP).<br /> If no protocol is specified, the default is TCP. The format is:`[host]:port[/tcp\|/udp] | - | Yes | | `address` | Define the port, and optionally the hostname, on which to listen for incoming connections and packets.<br /> It also defines the protocol to use (TCP or UDP).<br /> If no protocol is specified, the default is TCP. The format is:`[host]:port[/tcp\|/udp] | - | Yes |
| `asDefault` | Mark the `entryPoint` to be in the list of default `entryPoints`.<br /> `entryPoints`in this list are used (by default) on HTTP and TCP routers that do not define their own `entryPoints` option.<br /> More information [here](#asdefault). | false | No | | `asDefault` | Mark the `entryPoint` to be in the list of default `entryPoints`.<br /> `entryPoints`in this list are used (by default) on HTTP and TCP routers that do not define their own `entryPoints` option.<br /> More information [here](#asdefault). | false | No |
| `forwardedHeaders.trustedIPs` | Set the IPs or CIDR from where Traefik trusts the forwarded headers information (`X-Forwarded-*`). | - | No | | `forwardedHeaders.trustedIPs` | Set the IPs or CIDR from where Traefik trusts the forwarded headers information (`X-Forwarded-*`). | - | No |
@ -92,11 +92,11 @@ additionalArguments:
| `http.redirections.`<br />`entryPoint.to` | The target element to enable (permanent) redirecting of all incoming requests on an entry point to another one. <br /> The target element can be an entry point name (ex: `websecure`), or a port (`:443`). | - | Yes | | `http.redirections.`<br />`entryPoint.to` | The target element to enable (permanent) redirecting of all incoming requests on an entry point to another one. <br /> The target element can be an entry point name (ex: `websecure`), or a port (`:443`). | - | Yes |
| `http.redirections.`<br />`entryPoint.scheme` | The target scheme to use for (permanent) redirection of all incoming requests. | https | No | | `http.redirections.`<br />`entryPoint.scheme` | The target scheme to use for (permanent) redirection of all incoming requests. | https | No |
| `http.redirections.`<br />`entryPoint.permanent` | Enable permanent redirecting of all incoming requests on an entry point to another one changing the scheme. <br /> The target element, it can be an entry point name (ex: `websecure`), or a port (`:443`). | false | No | | `http.redirections.`<br />`entryPoint.permanent` | Enable permanent redirecting of all incoming requests on an entry point to another one changing the scheme. <br /> The target element, it can be an entry point name (ex: `websecure`), or a port (`:443`). | false | No |
| `http.redirections.`<br />`entryPoint.priority` | Default priority applied to the routers attached to the `entryPoint`.| MaxInt32-1 (2147483646) | No | | `http.redirections.`<br />`entryPoint.priority` | Default priority applied to the routers attached to the `entryPoint`. | MaxInt32-1 (2147483646) | No |
| `http.encodeQuerySemicolons` | Enable query semicolons encoding. <br /> Use this option to avoid non-encoded semicolons to be interpreted as query parameter separators by Traefik. <br /> When using this option, the non-encoded semicolons characters in query will be transmitted encoded to the backend.<br /> More information [here](#encodequerysemicolons). | false | No | | `http.encodeQuerySemicolons` | Enable query semicolons encoding. <br /> Use this option to avoid non-encoded semicolons to be interpreted as query parameter separators by Traefik. <br /> When using this option, the non-encoded semicolons characters in query will be transmitted encoded to the backend.<br /> More information [here](#encodequerysemicolons). | false | No |
| `http.sanitizePath` | Defines whether to enable the request path sanitization.<br /> More information [here](#sanitizepath). | false | No | | `http.sanitizePath` | Defines whether to enable the request path sanitization.<br /> More information [here](#sanitizepath). | false | No |
| `http.middlewares` | Set the list of middlewares that are prepended by default to the list of middlewares of each router associated to the named entry point. <br />More information [here](#httpmiddlewares). | - | No | | `http.middlewares` | Set the list of middlewares that are prepended by default to the list of middlewares of each router associated to the named entry point. <br />More information [here](#httpmiddlewares). | - | No |
| `http.tls` | Enable TLS on every router attached to the `entryPoint`. <br /> If no certificate are set, a default self-signed certificate is generates by Traefik. <br /> We recommend to not use self signed certificates in production.| - | No | | `http.tls` | Enable TLS on every router attached to the `entryPoint`. <br /> If no certificate are set, a default self-signed certificate is generates by Traefik. <br /> We recommend to not use self signed certificates in production. | - | No |
| `http.tls.options` | Apply TLS options on every router attached to the `entryPoint`. <br /> The TLS options can be overidden per router. <br /> More information in the [dedicated section](../../routing/providers/kubernetes-crd.md#kind-tlsoption). | - | No | | `http.tls.options` | Apply TLS options on every router attached to the `entryPoint`. <br /> The TLS options can be overidden per router. <br /> More information in the [dedicated section](../../routing/providers/kubernetes-crd.md#kind-tlsoption). | - | No |
| `http.tls.certResolver` | Apply a certificate resolver on every router attached to the `entryPoint`. <br /> The TLS options can be overidden per router. <br /> More information in the [dedicated section](../install-configuration/tls/certificate-resolvers/overview.md). | - | No | | `http.tls.certResolver` | Apply a certificate resolver on every router attached to the `entryPoint`. <br /> The TLS options can be overidden per router. <br /> More information in the [dedicated section](../install-configuration/tls/certificate-resolvers/overview.md). | - | No |
| `http2.maxConcurrentStreams` | Set the number of concurrent streams per connection that each client is allowed to initiate. <br /> The value must be greater than zero. | 250 | No | | `http2.maxConcurrentStreams` | Set the number of concurrent streams per connection that each client is allowed to initiate. <br /> The value must be greater than zero. | 250 | No |
@ -105,9 +105,10 @@ additionalArguments:
| `observability.accessLogs` | Defines whether a router attached to this EntryPoint produces access-logs by default. Nonetheless, a router defining its own observability configuration will opt-out from this default. | true | No | | `observability.accessLogs` | Defines whether a router attached to this EntryPoint produces access-logs by default. Nonetheless, a router defining its own observability configuration will opt-out from this default. | true | No |
| `observability.metrics` | Defines whether a router attached to this EntryPoint produces metrics by default. Nonetheless, a router defining its own observability configuration will opt-out from this default. | true | No | | `observability.metrics` | Defines whether a router attached to this EntryPoint produces metrics by default. Nonetheless, a router defining its own observability configuration will opt-out from this default. | true | No |
| `observability.tracing` | Defines whether a router attached to this EntryPoint produces traces by default. Nonetheless, a router defining its own observability configuration will opt-out from this default. | true | No | | `observability.tracing` | Defines whether a router attached to this EntryPoint produces traces by default. Nonetheless, a router defining its own observability configuration will opt-out from this default. | true | No |
| `observability.traceVerbosity` | Defines the tracing verbosity level for routers attached to this EntryPoint. Possible values: `minimal` (default), `detailed`. Routers can override this value in their own observability configuration. <br /> More information [here](#traceverbosity). | minimal | No |
| `proxyProtocol.trustedIPs` | Enable PROXY protocol with Trusted IPs. <br /> Traefik supports [PROXY protocol](https://www.haproxy.org/download/2.0/doc/proxy-protocol.txt) version 1 and 2. <br /> If PROXY protocol header parsing is enabled for the entry point, this entry point can accept connections with or without PROXY protocol headers. <br /> If the PROXY protocol header is passed, then the version is determined automatically.<br /> More information [here](#proxyprotocol-and-load-balancers). | - | No | | `proxyProtocol.trustedIPs` | Enable PROXY protocol with Trusted IPs. <br /> Traefik supports [PROXY protocol](https://www.haproxy.org/download/2.0/doc/proxy-protocol.txt) version 1 and 2. <br /> If PROXY protocol header parsing is enabled for the entry point, this entry point can accept connections with or without PROXY protocol headers. <br /> If the PROXY protocol header is passed, then the version is determined automatically.<br /> More information [here](#proxyprotocol-and-load-balancers). | - | No |
| `proxyProtocol.insecure` | Enable PROXY protocol trusting every incoming connection. <br /> Every remote client address will be replaced (`trustedIPs`) won't have any effect). <br /> Traefik supports [PROXY protocol](https://www.haproxy.org/download/2.0/doc/proxy-protocol.txt) version 1 and 2. <br /> If PROXY protocol header parsing is enabled for the entry point, this entry point can accept connections with or without PROXY protocol headers. <br /> If the PROXY protocol header is passed, then the version is determined automatically.<br />We recommend to use this option only for tests purposes, not in production.<br /> More information [here](#proxyprotocol-and-load-balancers). | - | No | | `proxyProtocol.insecure` | Enable PROXY protocol trusting every incoming connection. <br /> Every remote client address will be replaced (`trustedIPs`) won't have any effect). <br /> Traefik supports [PROXY protocol](https://www.haproxy.org/download/2.0/doc/proxy-protocol.txt) version 1 and 2. <br /> If PROXY protocol header parsing is enabled for the entry point, this entry point can accept connections with or without PROXY protocol headers. <br /> If the PROXY protocol header is passed, then the version is determined automatically.<br />We recommend to use this option only for tests purposes, not in production.<br /> More information [here](#proxyprotocol-and-load-balancers). | - | No |
| `reusePort` | Enable `entryPoints` from the same or different processes listening on the same TCP/UDP port by utilizing the `SO_REUSEPORT` socket option. <br /> It also allows the kernel to act like a load balancer to distribute incoming connections between entry points..<br /> More information [here](#reuseport). | false | No | | `reusePort` | Enable `entryPoints` from the same or different processes listening on the same TCP/UDP port by utilizing the `SO_REUSEPORT` socket option. <br /> It also allows the kernel to act like a load balancer to distribute incoming connections between entry points.<br /> More information [here](#reuseport). | false | No |
| `transport.`<br />`respondingTimeouts.`<br />`readTimeout` | Set the timeouts for incoming requests to the Traefik instance. This is the maximum duration for reading the entire request, including the body. Setting them has no effect for UDP `entryPoints`.<br /> If zero, no timeout exists. <br />Can be provided in a format supported by [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration) or as raw values (digits).<br />If no units are provided, the value is parsed assuming seconds. | 60s (seconds) | No | | `transport.`<br />`respondingTimeouts.`<br />`readTimeout` | Set the timeouts for incoming requests to the Traefik instance. This is the maximum duration for reading the entire request, including the body. Setting them has no effect for UDP `entryPoints`.<br /> If zero, no timeout exists. <br />Can be provided in a format supported by [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration) or as raw values (digits).<br />If no units are provided, the value is parsed assuming seconds. | 60s (seconds) | No |
| `transport.`<br />`respondingTimeouts.`<br />`writeTimeout` | Maximum duration before timing out writes of the response. <br /> It covers the time from the end of the request header read to the end of the response write. <br /> If zero, no timeout exists. <br />Can be provided in a format supported by [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration) or as raw values (digits).<br />If no units are provided, the value is parsed assuming seconds. | 0s (seconds) | No | | `transport.`<br />`respondingTimeouts.`<br />`writeTimeout` | Maximum duration before timing out writes of the response. <br /> It covers the time from the end of the request header read to the end of the response write. <br /> If zero, no timeout exists. <br />Can be provided in a format supported by [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration) or as raw values (digits).<br />If no units are provided, the value is parsed assuming seconds. | 0s (seconds) | No |
| `transport.`<br />`respondingTimeouts.`<br />`idleTimeout` | Maximum duration an idle (keep-alive) connection will remain idle before closing itself. <br /> If zero, no timeout exists <br />Can be provided in a format supported by [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration) or as raw values (digits).<br />If no units are provided, the value is parsed assuming seconds | 180s (seconds) | No | | `transport.`<br />`respondingTimeouts.`<br />`idleTimeout` | Maximum duration an idle (keep-alive) connection will remain idle before closing itself. <br /> If zero, no timeout exists <br />Can be provided in a format supported by [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration) or as raw values (digits).<br />If no units are provided, the value is parsed assuming seconds | 180s (seconds) | No |
@ -115,7 +116,7 @@ additionalArguments:
| `transport.`<br />`lifeCycle.`<br />`requestAcceptGraceTimeout` | Set the duration to keep accepting requests prior to initiating the graceful termination period (as defined by the `transportlifeCycle.graceTimeOut` option). <br /> This option is meant to give downstream load-balancers sufficient time to take Traefik out of rotation. <br />Can be provided in a format supported by [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration) or as raw values (digits).<br />If no units are provided, the value is parsed assuming seconds | 0s (seconds) | No | | `transport.`<br />`lifeCycle.`<br />`requestAcceptGraceTimeout` | Set the duration to keep accepting requests prior to initiating the graceful termination period (as defined by the `transportlifeCycle.graceTimeOut` option). <br /> This option is meant to give downstream load-balancers sufficient time to take Traefik out of rotation. <br />Can be provided in a format supported by [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration) or as raw values (digits).<br />If no units are provided, the value is parsed assuming seconds | 0s (seconds) | No |
| `transport.`<br />`keepAliveMaxRequests` | Set the maximum number of requests Traefik can handle before sending a `Connection: Close` header to the client (for HTTP2, Traefik sends a GOAWAY). <br /> Zero means no limit. | 0 | No | | `transport.`<br />`keepAliveMaxRequests` | Set the maximum number of requests Traefik can handle before sending a `Connection: Close` header to the client (for HTTP2, Traefik sends a GOAWAY). <br /> Zero means no limit. | 0 | No |
| `transport.`<br />`keepAliveMaxTime` | Set the maximum duration Traefik can handle requests before sending a `Connection: Close` header to the client (for HTTP2, Traefik sends a GOAWAY). Zero means no limit. | 0s (seconds) | No | | `transport.`<br />`keepAliveMaxTime` | Set the maximum duration Traefik can handle requests before sending a `Connection: Close` header to the client (for HTTP2, Traefik sends a GOAWAY). Zero means no limit. | 0s (seconds) | No |
| `udp.timeout` | Define how long to wait on an idle session before releasing the related resources. <br />The Timeout value must be greater than zero. | 3s (seconds)| No | | `udp.timeout` | Define how long to wait on an idle session before releasing the related resources. <br />The Timeout value must be greater than zero. | 3s (seconds) | No |
### asDefault ### asDefault
@ -213,7 +214,7 @@ only routers with TLS enabled will be usable with HTTP/3.
### ProxyProtocol and Load-Balancers ### ProxyProtocol and Load-Balancers
The replacement of the remote client address will occur only for IP addresses listed in `trustedIPs`. This is where yoåu specify your load balancer IPs or CIDR ranges. The replacement of the remote client address will occur only for IP addresses listed in `trustedIPs`. This is where you specify your load balancer IPs or CIDR ranges.
When queuing Traefik behind another load-balancer, make sure to configure When queuing Traefik behind another load-balancer, make sure to configure
PROXY protocol on both sides. PROXY protocol on both sides.
@ -271,3 +272,13 @@ Use the `reusePort` option with the other option `transport.lifeCycle.gracetimeo
to do to do
canary deployments against Traefik itself. Like upgrading Traefik version canary deployments against Traefik itself. Like upgrading Traefik version
or reloading the static configuration without any service downtime. or reloading the static configuration without any service downtime.
#### Trace Verbosity
`observability.traceVerbosity` defines the tracing verbosity level for routers attached to this EntryPoint.
Routers can override this value in their own observability configuration.
Possible values are:
- `minimal`: produces a single server span and one client span for each request processed by a router.
- `detailed`: enables the creation of additional spans for each middleware executed for each request processed by a router.

View File

@ -27,16 +27,6 @@ $ traefik healthcheck
OK: http://:8082/ping OK: http://:8082/ping
``` ```
### URL Option
The URL to check can be specified with the `--url` flag, which defaults to `http://localhost:8080/ping`.
Example:
```sh
traefik healthcheck --url=http://localhost:8080/ping
```
## Ping ## Ping
The `/ping` health-check URL is enabled with the command-line `--ping` or config file option `[ping]`. The `/ping` health-check URL is enabled with the command-line `--ping` or config file option `[ping]`.

View File

@ -97,8 +97,10 @@ log:
#### Configuration Options #### Configuration Options
| Field | Description | Default | Required | | Field | Description | Default | Required |
|:-----------|:-----------------------------------------------------------------------------|:--------|:---------| |:---------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------|:---------------------------------|:---------|
| `log.otlp.http` | This instructs the exporter to send logs to the OpenTelemetry Collector using HTTP.| | No | | `log.otlp.serviceName` | Service name used in selected backend. | "traefik" | No |
| `log.otlp.resourceAttributes` | Defines additional resource attributes to be sent to the collector. | [] | No |
| `log.otlp.http` | This instructs the exporter to send logs to the OpenTelemetry Collector using HTTP. | | No |
| `log.otlp.http.endpoint` | The endpoint of the OpenTelemetry Collector. (format=`<scheme>://<host>:<port><path>`) | `https://localhost:4318/v1/logs` | No | | `log.otlp.http.endpoint` | The endpoint of the OpenTelemetry Collector. (format=`<scheme>://<host>:<port><path>`) | `https://localhost:4318/v1/logs` | No |
| `log.otlp.http.headers` | Additional headers sent with logs by the exporter to the OpenTelemetry Collector. | [ ] | No | | `log.otlp.http.headers` | Additional headers sent with logs by the exporter to the OpenTelemetry Collector. | [ ] | No |
| `log.otlp.http.tls` | Defines the Client TLS configuration used by the exporter to send logs to the OpenTelemetry Collector. | | No | | `log.otlp.http.tls` | Defines the Client TLS configuration used by the exporter to send logs to the OpenTelemetry Collector. | | No |
@ -106,7 +108,7 @@ log:
| `log.otlp.http.tls.cert` | The path to the certificate to use for the OpenTelemetry Collector. | | No | | `log.otlp.http.tls.cert` | The path to the certificate to use for the OpenTelemetry Collector. | | No |
| `log.otlp.http.tls.key` | The path to the key to use for the OpenTelemetry Collector. | | No | | `log.otlp.http.tls.key` | The path to the key to use for the OpenTelemetry Collector. | | No |
| `log.otlp.http.tls.insecureSkipVerify` | Instructs the OpenTelemetry Collector to accept any certificate presented by the server regardless of the hostname in the certificate. | false | No | | `log.otlp.http.tls.insecureSkipVerify` | Instructs the OpenTelemetry Collector to accept any certificate presented by the server regardless of the hostname in the certificate. | false | No |
| `log.otlp.grpc` | This instructs the exporter to send logs to the OpenTelemetry Collector using gRPC.| | No | | `log.otlp.grpc` | This instructs the exporter to send logs to the OpenTelemetry Collector using gRPC. | | No |
| `log.otlp.grpc.endpoint` | The endpoint of the OpenTelemetry Collector. (format=`<host>:<port>`) | `localhost:4317` | No | | `log.otlp.grpc.endpoint` | The endpoint of the OpenTelemetry Collector. (format=`<host>:<port>`) | `localhost:4317` | No |
| `log.otlp.grpc.headers` | Additional headers sent with logs by the exporter to the OpenTelemetry Collector. | [ ] | No | | `log.otlp.grpc.headers` | Additional headers sent with logs by the exporter to the OpenTelemetry Collector. | [ ] | No |
| `log.otlp.grpc.insecure` | Instructs the exporter to send logs to the OpenTelemetry Collector using an insecure protocol. | false | No | | `log.otlp.grpc.insecure` | Instructs the exporter to send logs to the OpenTelemetry Collector using an insecure protocol. | false | No |
@ -257,8 +259,10 @@ accesslog:
#### Configuration Options #### Configuration Options
| Field | Description | Default | Required | | Field | Description | Default | Required |
|:-----------|:--------------------------|:--------|:---------| |:---------------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------|:---------------------------------|:---------|
| `accesslog.otlp.http` | This instructs the exporter to send access logs to the OpenTelemetry Collector using HTTP.| | No | | `accesslog.otlp.serviceName` | Defines the service name resource attribute. | "traefik" | No |
| `accesslog.otlp.resourceAttributes` | Defines additional resource attributes to be sent to the collector. | [] | No |
| `accesslog.otlp.http` | This instructs the exporter to send access logs to the OpenTelemetry Collector using HTTP. | | No |
| `accesslog.otlp.http.endpoint` | The endpoint of the OpenTelemetry Collector. (format=`<scheme>://<host>:<port><path>`) | `https://localhost:4318/v1/logs` | No | | `accesslog.otlp.http.endpoint` | The endpoint of the OpenTelemetry Collector. (format=`<scheme>://<host>:<port><path>`) | `https://localhost:4318/v1/logs` | No |
| `accesslog.otlp.http.headers` | Additional headers sent with access logs by the exporter to the OpenTelemetry Collector. | [ ] | No | | `accesslog.otlp.http.headers` | Additional headers sent with access logs by the exporter to the OpenTelemetry Collector. | [ ] | No |
| `accesslog.otlp.http.tls` | Defines the Client TLS configuration used by the exporter to send access logs to the OpenTelemetry Collector. | | No | | `accesslog.otlp.http.tls` | Defines the Client TLS configuration used by the exporter to send access logs to the OpenTelemetry Collector. | | No |
@ -266,7 +270,7 @@ accesslog:
| `accesslog.otlp.http.tls.cert` | The path to the certificate to use for the OpenTelemetry Collector. | | No | | `accesslog.otlp.http.tls.cert` | The path to the certificate to use for the OpenTelemetry Collector. | | No |
| `accesslog.otlp.http.tls.key` | The path to the key to use for the OpenTelemetry Collector. | | No | | `accesslog.otlp.http.tls.key` | The path to the key to use for the OpenTelemetry Collector. | | No |
| `accesslog.otlp.http.tls.insecureSkipVerify` | Instructs the OpenTelemetry Collector to accept any certificate presented by the server regardless of the hostname in the certificate. | false | No | | `accesslog.otlp.http.tls.insecureSkipVerify` | Instructs the OpenTelemetry Collector to accept any certificate presented by the server regardless of the hostname in the certificate. | false | No |
| `accesslog.otlp.grpc` | This instructs the exporter to send access logs to the OpenTelemetry Collector using gRPC.| | No | | `accesslog.otlp.grpc` | This instructs the exporter to send access logs to the OpenTelemetry Collector using gRPC. | | No |
| `accesslog.otlp.grpc.endpoint` | The endpoint of the OpenTelemetry Collector. (format=`<host>:<port>`) | `localhost:4317` | No | | `accesslog.otlp.grpc.endpoint` | The endpoint of the OpenTelemetry Collector. (format=`<host>:<port>`) | `localhost:4317` | No |
| `accesslog.otlp.grpc.headers` | Additional headers sent with access logs by the exporter to the OpenTelemetry Collector. | [ ] | No | | `accesslog.otlp.grpc.headers` | Additional headers sent with access logs by the exporter to the OpenTelemetry Collector. | [ ] | No |
| `accesslog.otlp.grpc.insecure` | Instructs the exporter to send access logs to the OpenTelemetry Collector using an insecure protocol. | false | No | | `accesslog.otlp.grpc.insecure` | Instructs the exporter to send access logs to the OpenTelemetry Collector using an insecure protocol. | false | No |

View File

@ -61,11 +61,13 @@ metrics:
### Configuration Options ### Configuration Options
| Field | Description | Default | Required | | Field | Description | Default | Required |
|:-----------|---------------|:--------|:---------| |:-------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------|:---------------------------------------------------|:---------|
| `metrics.addInternals` | Enables metrics for internal resources (e.g.: `ping@internal`). | false | No | | `metrics.addInternals` | Enables metrics for internal resources (e.g.: `ping@internal`). | false | No |
| `metrics.otlp.serviceName` | Defines the service name resource attribute. | "traefik" | No |
| `metrics.otlp.resourceAttributes` | Defines additional resource attributes to be sent to the collector. | [] | No |
| `metrics.otlp.addEntryPointsLabels` | Enable metrics on entry points. | true | No | | `metrics.otlp.addEntryPointsLabels` | Enable metrics on entry points. | true | No |
| `metrics.otlp.addRoutersLabels` | Enable metrics on routers. | false | No | | `metrics.otlp.addRoutersLabels` | Enable metrics on routers. | false | No |
| `metrics.otlp.addServicesLabels` | Enable metrics on services.| true | No | | `metrics.otlp.addServicesLabels` | Enable metrics on services. | true | No |
| `metrics.otlp.explicitBoundaries` | Explicit boundaries for Histogram data points. | ".005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10" | No | | `metrics.otlp.explicitBoundaries` | Explicit boundaries for Histogram data points. | ".005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10" | No |
| `metrics.otlp.pushInterval` | Interval at which metrics are sent to the OpenTelemetry Collector. | 10s | No | | `metrics.otlp.pushInterval` | Interval at which metrics are sent to the OpenTelemetry Collector. | 10s | No |
| `metrics.otlp.http` | This instructs the exporter to send the metrics to the OpenTelemetry Collector using HTTP.<br /> Setting the sub-options with their default values. | null/false | No | | `metrics.otlp.http` | This instructs the exporter to send the metrics to the OpenTelemetry Collector using HTTP.<br /> Setting the sub-options with their default values. | null/false | No |
@ -78,7 +80,7 @@ metrics:
| `metrics.otlp.grpc` | This instructs the exporter to send metrics to the OpenTelemetry Collector using gRPC. | null/false | No | | `metrics.otlp.grpc` | This instructs the exporter to send metrics to the OpenTelemetry Collector using gRPC. | null/false | No |
| `metrics.otlp.grpc.endpoint` | Address of the OpenTelemetry Collector to send metrics to.<br /> Format="`<host>:<port>`" | "localhost:4317" | Yes | | `metrics.otlp.grpc.endpoint` | Address of the OpenTelemetry Collector to send metrics to.<br /> Format="`<host>:<port>`" | "localhost:4317" | Yes |
| `metrics.otlp.grpc.headers` | Additional headers sent with metrics by the exporter to the OpenTelemetry Collector. | - | No | | `metrics.otlp.grpc.headers` | Additional headers sent with metrics by the exporter to the OpenTelemetry Collector. | - | No |
| `metrics.otlp.http.grpc.insecure` |Allows exporter to send metrics to the OpenTelemetry Collector without using a secured protocol. | false | Yes | | `metrics.otlp.http.grpc.insecure` | Allows exporter to send metrics to the OpenTelemetry Collector without using a secured protocol. | false | Yes |
| `metrics.otlp.grpc.tls.ca` | Path to the certificate authority used for the secure connection to the OpenTelemetry Collector,<br />it defaults to the system bundle. | - | No | | `metrics.otlp.grpc.tls.ca` | Path to the certificate authority used for the secure connection to the OpenTelemetry Collector,<br />it defaults to the system bundle. | - | No |
| `metrics.otlp.grpc.tls.cert` | Path to the public certificate used for the secure connection to the OpenTelemetry Collector.<br />When using this option, setting the `key` option is required. | - | No | | `metrics.otlp.grpc.tls.cert` | Path to the public certificate used for the secure connection to the OpenTelemetry Collector.<br />When using this option, setting the `key` option is required. | - | No |
| `metrics.otlp.grpc.tls.key` | This instructs the exporter to send the metrics to the OpenTelemetry Collector using HTTP.<br /> Setting the sub-options with their default values. | null/false | No | | `metrics.otlp.grpc.tls.key` | This instructs the exporter to send the metrics to the OpenTelemetry Collector using HTTP.<br /> Setting the sub-options with their default values. | null/false | No |

View File

@ -37,13 +37,13 @@ tracing: {}
## Configuration Options ## Configuration Options
| Field | Description | Default | Required | | Field | Description | Default | Required |
|:-------------------------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-----------------------------------|:---------| |:-------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-----------------------------------|:---------|
| `tracing.addInternals` | Enables tracing for internal resources (e.g.: `ping@internal`). | false | No | | `tracing.addInternals` | Enables tracing for internal resources (e.g.: `ping@internal`). | false | No |
| `tracing.serviceName` | Service name used in selected backend. | "traefik" | No | | `tracing.serviceName` | Defines the service name resource attribute. | "traefik" | No |
| `tracing.sampleRate` | The proportion of requests to trace, specified between 0.0 and 1.0. | 1.0 | No |
| `tracing.resourceAttributes` | Defines additional resource attributes to be sent to the collector. | [] | No | | `tracing.resourceAttributes` | Defines additional resource attributes to be sent to the collector. | [] | No |
| `tracing.capturedRequestHeaders` | Defines the list of request headers to add as attributes.<br />It applies to client and server kind spans.| [] | No | | `tracing.sampleRate` | The proportion of requests to trace, specified between 0.0 and 1.0. | 1.0 | No |
| `tracing.capturedResponseHeaders` | Defines the list of response headers to add as attributes.<br />It applies to client and server kind spans.| [] |False | | `tracing.capturedRequestHeaders` | Defines the list of request headers to add as attributes.<br />It applies to client and server kind spans. | [] | No |
| `tracing.capturedResponseHeaders` | Defines the list of response headers to add as attributes.<br />It applies to client and server kind spans. | [] | False |
| `tracing.safeQueryParams` | By default, all query parameters are redacted.<br />Defines the list of query parameters to not redact. | [] | No | | `tracing.safeQueryParams` | By default, all query parameters are redacted.<br />Defines the list of query parameters to not redact. | [] | No |
| `tracing.otlp.http` | This instructs the exporter to send the tracing to the OpenTelemetry Collector using HTTP.<br /> Setting the sub-options with their default values. | null/false | No | | `tracing.otlp.http` | This instructs the exporter to send the tracing to the OpenTelemetry Collector using HTTP.<br /> Setting the sub-options with their default values. | null/false | No |
| `tracing.otlp.http.endpoint` | URL of the OpenTelemetry Collector to send tracing to.<br /> Format="`<scheme>://<host>:<port><path>`" | "http://localhost:4318/v1/tracing" | Yes | | `tracing.otlp.http.endpoint` | URL of the OpenTelemetry Collector to send tracing to.<br /> Format="`<scheme>://<host>:<port><path>`" | "http://localhost:4318/v1/tracing" | Yes |
@ -51,12 +51,12 @@ tracing: {}
| `tracing.otlp.http.tls.ca` | Path to the certificate authority used for the secure connection to the OpenTelemetry Collector, it defaults to the system bundle. | "" | No | | `tracing.otlp.http.tls.ca` | Path to the certificate authority used for the secure connection to the OpenTelemetry Collector, it defaults to the system bundle. | "" | No |
| `tracing.otlp.http.tls.cert` | Path to the public certificate used for the secure connection to the OpenTelemetry Collector. When using this option, setting the `key` option is required. | "" | No | | `tracing.otlp.http.tls.cert` | Path to the public certificate used for the secure connection to the OpenTelemetry Collector. When using this option, setting the `key` option is required. | "" | No |
| `tracing.otlp.http.tls.key` | This instructs the exporter to send the tracing to the OpenTelemetry Collector using HTTP.<br /> Setting the sub-options with their default values. | ""null/false "" | No | | `tracing.otlp.http.tls.key` | This instructs the exporter to send the tracing to the OpenTelemetry Collector using HTTP.<br /> Setting the sub-options with their default values. | ""null/false "" | No |
| `tracing.otlp.http.tls.insecureskipverify` |If `insecureSkipVerify` is `true`, the TLS connection to the OpenTelemetry Collector accepts any certificate presented by the server regardless of the hostnames it covers. | false | Yes | | `tracing.otlp.http.tls.insecureskipverify` | If `insecureSkipVerify` is `true`, the TLS connection to the OpenTelemetry Collector accepts any certificate presented by the server regardless of the hostnames it covers. | false | Yes |
| `tracing.otlp.grpc` | This instructs the exporter to send tracing to the OpenTelemetry Collector using gRPC. | false | No | | `tracing.otlp.grpc` | This instructs the exporter to send tracing to the OpenTelemetry Collector using gRPC. | false | No |
| `tracing.otlp.grpc.endpoint` | Address of the OpenTelemetry Collector to send tracing to.<br /> Format="`<host>:<port>`" | "localhost:4317" | Yes | | `tracing.otlp.grpc.endpoint` | Address of the OpenTelemetry Collector to send tracing to.<br /> Format="`<host>:<port>`" | "localhost:4317" | Yes |
| `tracing.otlp.grpc.headers` | Additional headers sent with tracing by the exporter to the OpenTelemetry Collector. | [] | No | | `tracing.otlp.grpc.headers` | Additional headers sent with tracing by the exporter to the OpenTelemetry Collector. | [] | No |
| `tracing.otlp.grpc.insecure` |Allows exporter to send tracing to the OpenTelemetry Collector without using a secured protocol. | false | Yes | | `tracing.otlp.grpc.insecure` | Allows exporter to send tracing to the OpenTelemetry Collector without using a secured protocol. | false | Yes |
| `tracing.otlp.grpc.tls.ca` | Path to the certificate authority used for the secure connection to the OpenTelemetry Collector, it defaults to the system bundle. | "" | No | | `tracing.otlp.grpc.tls.ca` | Path to the certificate authority used for the secure connection to the OpenTelemetry Collector, it defaults to the system bundle. | "" | No |
| `tracing.otlp.grpc.tls.cert` | Path to the public certificate used for the secure connection to the OpenTelemetry Collector. When using this option, setting the `key` option is required. | "" | No | | `tracing.otlp.grpc.tls.cert` | Path to the public certificate used for the secure connection to the OpenTelemetry Collector. When using this option, setting the `key` option is required. | "" | No |
| `tracing.otlp.grpc.tls.key` | This instructs the exporter to send the tracing to the OpenTelemetry Collector using HTTP.<br /> Setting the sub-options with their default values. | ""null/false "" | No | | `tracing.otlp.grpc.tls.key` | This instructs the exporter to send the tracing to the OpenTelemetry Collector using HTTP.<br /> Setting the sub-options with their default values. | ""null/false "" | No |
| `tracing.otlp.grpc.tls.insecureskipverify` |If `insecureSkipVerify` is `true`, the TLS connection to the OpenTelemetry Collector accepts any certificate presented by the server regardless of the hostnames it covers. | false | Yes | | `tracing.otlp.grpc.tls.insecureskipverify` | If `insecureSkipVerify` is `true`, the TLS connection to the OpenTelemetry Collector accepts any certificate presented by the server regardless of the hostnames it covers. | false | Yes |

View File

@ -270,6 +270,10 @@ created. If the expression is empty, all detected containers are included.
The expression syntax is based on the `Label("key", "value")`, and `LabelRegex("key", "value")` functions, The expression syntax is based on the `Label("key", "value")`, and `LabelRegex("key", "value")` functions,
as well as the usual boolean logic, as shown in examples below. as well as the usual boolean logic, as shown in examples below.
!!! tip "Constraints key limitations"
Note that `traefik.*` is a reserved label namespace for configuration and can not be used as a key for custom constraints.
??? example "Constraints Expression Examples" ??? example "Constraints Expression Examples"
```toml ```toml

View File

@ -112,6 +112,10 @@ created. If the expression is empty, all detected services are included.
The expression syntax is based on the ```Tag(`tag`)```, and ```TagRegex(`tag`)``` functions, The expression syntax is based on the ```Tag(`tag`)```, and ```TagRegex(`tag`)``` functions,
as well as the usual boolean logic, as shown in examples below. as well as the usual boolean logic, as shown in examples below.
!!! tip "Constraints key limitations"
Note that `traefik.*` is a reserved label namespace for configuration and can not be used as a key for custom constraints.
??? example "Constraints Expression Examples" ??? example "Constraints Expression Examples"
```toml ```toml

View File

@ -191,6 +191,10 @@ created. If the expression is empty, all detected services are included.
The expression syntax is based on the ```Tag(`tag`)```, and ```TagRegex(`tag`)``` functions, The expression syntax is based on the ```Tag(`tag`)```, and ```TagRegex(`tag`)``` functions,
as well as the usual boolean logic, as shown in examples below. as well as the usual boolean logic, as shown in examples below.
!!! tip "Constraints key limitations"
Note that `traefik.*` is a reserved label namespace for configuration and can not be used as a key for custom constraints.
??? example "Constraints Expression Examples" ??? example "Constraints Expression Examples"
```toml ```toml

View File

@ -49,6 +49,10 @@ If the expression is empty, all detected containers are included.
The expression syntax is based on the `Label("key", "value")`, and `LabelRegex("key", "value")` functions, The expression syntax is based on the `Label("key", "value")`, and `LabelRegex("key", "value")` functions,
as well as the usual boolean logic, as shown in examples below. as well as the usual boolean logic, as shown in examples below.
!!! tip "Constraints key limitations"
Note that `traefik.*` is a reserved label namespace for configuration and can not be used as a key for custom constraints.
??? example "Constraints Expression Examples" ??? example "Constraints Expression Examples"
```toml ```toml

View File

@ -276,6 +276,10 @@ created. If the expression is empty, all detected containers are included.
The expression syntax is based on the `Label("key", "value")`, and `LabelRegex("key", "value")` functions, The expression syntax is based on the `Label("key", "value")`, and `LabelRegex("key", "value")` functions,
as well as the usual boolean logic, as shown in examples below. as well as the usual boolean logic, as shown in examples below.
!!! tip "Constraints key limitations"
Note that `traefik.*` is a reserved label namespace for configuration and can not be used as a key for custom constraints.
??? example "Constraints Expression Examples" ??? example "Constraints Expression Examples"
```toml ```toml

View File

@ -36,6 +36,7 @@ http:
metrics: false metrics: false
accessLogs: false accessLogs: false
tracing: false tracing: false
traceVerbosity: detailed
``` ```
```yaml tab="Structured (TOML)" ```yaml tab="Structured (TOML)"
@ -47,6 +48,7 @@ http:
metrics = false metrics = false
accessLogs = false accessLogs = false
tracing = false tracing = false
traceVerbosity = "detailed"
``` ```
```yaml tab="Labels" ```yaml tab="Labels"
@ -56,6 +58,7 @@ labels:
- "traefik.http.routers.my-router.observability.metrics=false" - "traefik.http.routers.my-router.observability.metrics=false"
- "traefik.http.routers.my-router.observability.accessLogs=false" - "traefik.http.routers.my-router.observability.accessLogs=false"
- "traefik.http.routers.my-router.observability.tracing=false" - "traefik.http.routers.my-router.observability.tracing=false"
- "traefik.http.routers.my-router.observability.traceVerbosity=detailed"
``` ```
```json tab="Tags" ```json tab="Tags"
@ -66,7 +69,8 @@ labels:
"traefik.http.routers.my-router.service=service-foo", "traefik.http.routers.my-router.service=service-foo",
"traefik.http.routers.my-router.observability.metrics=false", "traefik.http.routers.my-router.observability.metrics=false",
"traefik.http.routers.my-router.observability.accessLogs=false", "traefik.http.routers.my-router.observability.accessLogs=false",
"traefik.http.routers.my-router.observability.tracing=false" "traefik.http.routers.my-router.observability.tracing=false",
"traefik.http.routers.my-router.observability.traceVerbosity=detailed"
] ]
} }
``` ```
@ -74,7 +78,17 @@ labels:
## Configuration Options ## Configuration Options
| Field | Description | Default | Required | | Field | Description | Default | Required |
|:------|:------------|:--------|:---------| |:-----------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:----------|:---------|
| `accessLogs` | The `accessLogs` option controls whether the router will produce access-logs. | `true` | No | | `accessLogs` | The `accessLogs` option controls whether the router will produce access-logs. | `true` | No |
| `metrics` | The `metrics` option controls whether the router will produce metrics. | `true` | No | | `metrics` | The `metrics` option controls whether the router will produce metrics. | `true` | No |
| `tracing` | The `tracing` option controls whether the router will produce traces. | `true` | No | | `tracing` | The `tracing` option controls whether the router will produce traces. | `true` | No |
| `traceVerbosity` | The `traceVerbosity` option controls the tracing verbosity level for the router. Possible values: `minimal` (default), `detailed`. If not set, the value is inherited from the entryPoint. | `minimal` | No |
#### traceVerbosity
`observability.traceVerbosity` defines the tracing verbosity level for the router.
Possible values are:
- `minimal`: produces a single server span and one client span for each request processed by a router.
- `detailed`: enables the creation of additional spans for each middleware executed for each request processed by a router.

View File

@ -106,7 +106,7 @@ tls:
### Curve Preferences ### Curve Preferences
This option allows to set the preferred elliptic curves in a specific order. This option allows to set the preferred elliptic curves.
The names of the curves defined by [`crypto`](https://godoc.org/crypto/tls#CurveID) (e.g. `CurveP521`) and the [RFC defined names](https://tools.ietf.org/html/rfc8446#section-4.2.7) (e. g. `secp521r1`) can be used. The names of the curves defined by [`crypto`](https://godoc.org/crypto/tls#CurveID) (e.g. `CurveP521`) and the [RFC defined names](https://tools.ietf.org/html/rfc8446#section-4.2.7) (e. g. `secp521r1`) can be used.

View File

@ -51,7 +51,7 @@ spec:
| `minVersion` | Minimum TLS version that is acceptable. | "VersionTLS12" | No | | `minVersion` | Minimum TLS version that is acceptable. | "VersionTLS12" | No |
| `maxVersion` | Maximum TLS version that is acceptable.<br />We do not recommend setting this option to disable TLS 1.3. | | No | | `maxVersion` | Maximum TLS version that is acceptable.<br />We do not recommend setting this option to disable TLS 1.3. | | No |
| `cipherSuites` | List of supported [cipher suites](https://godoc.org/crypto/tls#pkg-constants) for TLS versions up to TLS 1.2.<br />[Cipher suites defined for TLS 1.2 and below cannot be used in TLS 1.3, and vice versa.](https://tools.ietf.org/html/rfc8446)<br />With TLS 1.3, [the cipher suites are not configurable](https://golang.org/doc/go1.12#tls_1_3) (all supported cipher suites are safe in this case). | | No | | `cipherSuites` | List of supported [cipher suites](https://godoc.org/crypto/tls#pkg-constants) for TLS versions up to TLS 1.2.<br />[Cipher suites defined for TLS 1.2 and below cannot be used in TLS 1.3, and vice versa.](https://tools.ietf.org/html/rfc8446)<br />With TLS 1.3, [the cipher suites are not configurable](https://golang.org/doc/go1.12#tls_1_3) (all supported cipher suites are safe in this case). | | No |
| `curvePreferences` | List of the elliptic curves references that will be used in an ECDHE handshake, in preference order.<br />Use curves names from [`crypto`](https://godoc.org/crypto/tls#CurveID) or the [RFC](https://tools.ietf.org/html/rfc8446#section-4.2.7).<br />See [CurveID](https://godoc.org/crypto/tls#CurveID) for more information. | | No | | `curvePreferences` | List of the elliptic curves references that will be used in an ECDHE handshake.<br />Use curves names from [`crypto`](https://godoc.org/crypto/tls#CurveID) or the [RFC](https://tools.ietf.org/html/rfc8446#section-4.2.7).<br />See [CurveID](https://godoc.org/crypto/tls#CurveID) for more information. | | No |
| `clientAuth.secretNames` | Client Authentication (mTLS) option.<br />List of names of the referenced Kubernetes [Secrets](https://kubernetes.io/docs/concepts/configuration/secret/) (in TLSOption namespace).<br /> The secret must contain a certificate under either a `tls.ca` or a `ca.crt` key. | | No | | `clientAuth.secretNames` | Client Authentication (mTLS) option.<br />List of names of the referenced Kubernetes [Secrets](https://kubernetes.io/docs/concepts/configuration/secret/) (in TLSOption namespace).<br /> The secret must contain a certificate under either a `tls.ca` or a `ca.crt` key. | | No |
| `clientAuth.clientAuthType` | Client Authentication (mTLS) option.<br />Client authentication type to apply. Available values [here](#client-authentication-mtls). | | No | | `clientAuth.clientAuthType` | Client Authentication (mTLS) option.<br />Client authentication type to apply. Available values [here](#client-authentication-mtls). | | No |
| `sniStrict` | Allow rejecting connections from clients connections that do not specify a server_name extension.<br />The [default certificate](../../../http/tls/tls-certificates.md#default-certificate) is never served is the option is enabled. | false | No | | `sniStrict` | Allow rejecting connections from clients connections that do not specify a server_name extension.<br />The [default certificate](../../../http/tls/tls-certificates.md#default-certificate) is never served is the option is enabled. | false | No |
@ -60,7 +60,7 @@ spec:
### Client Authentication (mTLS) ### Client Authentication (mTLS)
The `clientAuth.clientAuthType` option governs the behaviour as follows: The `clientAuth.clientAuthType` option governs the behavior as follows:
- `NoClientCert`: disregards any client certificate. - `NoClientCert`: disregards any client certificate.
- `RequestClientCert`: asks for a certificate but proceeds anyway if none is provided. - `RequestClientCert`: asks for a certificate but proceeds anyway if none is provided.

View File

@ -296,99 +296,107 @@ Limitations or behavioral differences are indicated where relevant.
### Unsupported NGINX Annotations ### Unsupported NGINX Annotations
All other NGINX annotations not listed above, including but not limited to: !!! question "Want to Add Support for More Annotations?"
You can help extend support in two ways:
- [**Open a PR**](../../../contributing/submitting-pull-requests.md) with the new annotation support.
- **Reach out** to the [Traefik Labs support team](https://info.traefik.io/request-commercial-support?cta=doc).
All contributions and suggestions are welcome — let's build this together!
| Annotation | Notes | | Annotation | Notes |
|-----------------------------------------------------------------------------|------------------------------------------------------| |-----------------------------------------------------------------------------|------------------------------------------------------|
| `nginx.ingress.kubernetes.io/app-root` | Not supported. | | `nginx.ingress.kubernetes.io/app-root` | Not supported yet. |
| `nginx.ingress.kubernetes.io/affinity-canary-behavior` | Not supported. | | `nginx.ingress.kubernetes.io/affinity-canary-behavior` | Not supported yet. |
| `nginx.ingress.kubernetes.io/auth-tls-secret` | Not supported. | | `nginx.ingress.kubernetes.io/auth-tls-secret` | Not supported yet. |
| `nginx.ingress.kubernetes.io/auth-tls-verify-depth` | Not supported. | | `nginx.ingress.kubernetes.io/auth-tls-verify-depth` | Not supported yet. |
| `nginx.ingress.kubernetes.io/auth-tls-verify-client` | Not supported. | | `nginx.ingress.kubernetes.io/auth-tls-verify-client` | Not supported yet. |
| `nginx.ingress.kubernetes.io/auth-tls-error-page` | Not supported. | | `nginx.ingress.kubernetes.io/auth-tls-error-page` | Not supported yet. |
| `nginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream` | Not supported. | | `nginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream` | Not supported yet. |
| `nginx.ingress.kubernetes.io/auth-tls-match-cn` | Not supported. | | `nginx.ingress.kubernetes.io/auth-tls-match-cn` | Not supported yet. |
| `nginx.ingress.kubernetes.io/auth-cache-key` | Not supported. | | `nginx.ingress.kubernetes.io/auth-cache-key` | Not supported yet. |
| `nginx.ingress.kubernetes.io/auth-cache-duration` | Not supported. | | `nginx.ingress.kubernetes.io/auth-cache-duration` | Not supported yet. |
| `nginx.ingress.kubernetes.io/auth-keepalive` | Not supported. | | `nginx.ingress.kubernetes.io/auth-keepalive` | Not supported yet. |
| `nginx.ingress.kubernetes.io/auth-keepalive-share-vars` | Not supported. | | `nginx.ingress.kubernetes.io/auth-keepalive-share-vars` | Not supported yet. |
| `nginx.ingress.kubernetes.io/auth-keepalive-requests` | Not supported. | | `nginx.ingress.kubernetes.io/auth-keepalive-requests` | Not supported yet. |
| `nginx.ingress.kubernetes.io/auth-keepalive-timeout` | Not supported. | | `nginx.ingress.kubernetes.io/auth-keepalive-timeout` | Not supported yet. |
| `nginx.ingress.kubernetes.io/auth-proxy-set-headers` | Not supported. | | `nginx.ingress.kubernetes.io/auth-proxy-set-headers` | Not supported yet. |
| `nginx.ingress.kubernetes.io/auth-snippet` | Not supported. | | `nginx.ingress.kubernetes.io/auth-snippet` | Not supported yet. |
| `nginx.ingress.kubernetes.io/enable-global-auth` | Not supported. | | `nginx.ingress.kubernetes.io/enable-global-auth` | Not supported yet. |
| `nginx.ingress.kubernetes.io/canary` | Not supported. | | `nginx.ingress.kubernetes.io/canary` | Not supported yet. |
| `nginx.ingress.kubernetes.io/canary-by-header` | Not supported. | | `nginx.ingress.kubernetes.io/canary-by-header` | Not supported yet. |
| `nginx.ingress.kubernetes.io/canary-by-header-value` | Not supported. | | `nginx.ingress.kubernetes.io/canary-by-header-value` | Not supported yet. |
| `nginx.ingress.kubernetes.io/canary-by-header-pattern` | Not supported. | | `nginx.ingress.kubernetes.io/canary-by-header-pattern` | Not supported yet. |
| `nginx.ingress.kubernetes.io/canary-by-cookie` | Not supported. | | `nginx.ingress.kubernetes.io/canary-by-cookie` | Not supported yet. |
| `nginx.ingress.kubernetes.io/canary-weight` | Not supported. | | `nginx.ingress.kubernetes.io/canary-weight` | Not supported yet. |
| `nginx.ingress.kubernetes.io/canary-weight-total` | Not supported. | | `nginx.ingress.kubernetes.io/canary-weight-total` | Not supported yet. |
| `nginx.ingress.kubernetes.io/client-body-buffer-size` | Not supported. | | `nginx.ingress.kubernetes.io/client-body-buffer-size` | Not supported yet. |
| `nginx.ingress.kubernetes.io/configuration-snippet` | Not supported. | | `nginx.ingress.kubernetes.io/configuration-snippet` | Not supported yet. |
| `nginx.ingress.kubernetes.io/custom-http-errors` | Not supported. | | `nginx.ingress.kubernetes.io/custom-http-errors` | Not supported yet. |
| `nginx.ingress.kubernetes.io/disable-proxy-intercept-errors` | Not supported. | | `nginx.ingress.kubernetes.io/disable-proxy-intercept-errors` | Not supported yet. |
| `nginx.ingress.kubernetes.io/default-backend` | Not supported; use `defaultBackend` in Ingress spec. | | `nginx.ingress.kubernetes.io/default-backend` | Not supported yet; use `defaultBackend` in Ingress spec. |
| `nginx.ingress.kubernetes.io/limit-rate-after` | Not supported. | | `nginx.ingress.kubernetes.io/limit-rate-after` | Not supported yet. |
| `nginx.ingress.kubernetes.io/limit-rate` | Not supported. | | `nginx.ingress.kubernetes.io/limit-rate` | Not supported yet. |
| `nginx.ingress.kubernetes.io/limit-whitelist` | Not supported. | | `nginx.ingress.kubernetes.io/limit-whitelist` | Not supported yet. |
| `nginx.ingress.kubernetes.io/limit-rps` | Not supported. | | `nginx.ingress.kubernetes.io/limit-rps` | Not supported yet. |
| `nginx.ingress.kubernetes.io/limit-rpm` | Not supported. | | `nginx.ingress.kubernetes.io/limit-rpm` | Not supported yet. |
| `nginx.ingress.kubernetes.io/limit-burst-multiplier` | Not supported. | | `nginx.ingress.kubernetes.io/limit-burst-multiplier` | Not supported yet. |
| `nginx.ingress.kubernetes.io/limit-connections` | Not supported. | | `nginx.ingress.kubernetes.io/limit-connections` | Not supported yet. |
| `nginx.ingress.kubernetes.io/global-rate-limit` | Not supported. | | `nginx.ingress.kubernetes.io/global-rate-limit` | Not supported yet. |
| `nginx.ingress.kubernetes.io/global-rate-limit-window` | Not supported. | | `nginx.ingress.kubernetes.io/global-rate-limit-window` | Not supported yet. |
| `nginx.ingress.kubernetes.io/global-rate-limit-key` | Not supported. | | `nginx.ingress.kubernetes.io/global-rate-limit-key` | Not supported yet. |
| `nginx.ingress.kubernetes.io/global-rate-limit-ignored-cidrs` | Not supported. | | `nginx.ingress.kubernetes.io/global-rate-limit-ignored-cidrs` | Not supported yet. |
| `nginx.ingress.kubernetes.io/permanent-redirect` | Not supported. | | `nginx.ingress.kubernetes.io/permanent-redirect` | Not supported yet. |
| `nginx.ingress.kubernetes.io/permanent-redirect-code` | Not supported. | | `nginx.ingress.kubernetes.io/permanent-redirect-code` | Not supported yet. |
| `nginx.ingress.kubernetes.io/temporal-redirect` | Not supported. | | `nginx.ingress.kubernetes.io/temporal-redirect` | Not supported yet. |
| `nginx.ingress.kubernetes.io/preserve-trailing-slash` | Not supported; Traefik preserves by default. | | `nginx.ingress.kubernetes.io/preserve-trailing-slash` | Not supported yet; Traefik preserves by default. |
| `nginx.ingress.kubernetes.io/proxy-cookie-domain` | Not supported. | | `nginx.ingress.kubernetes.io/proxy-cookie-domain` | Not supported yet. |
| `nginx.ingress.kubernetes.io/proxy-cookie-path` | Not supported. | | `nginx.ingress.kubernetes.io/proxy-cookie-path` | Not supported yet. |
| `nginx.ingress.kubernetes.io/proxy-connect-timeout` | Not supported. | | `nginx.ingress.kubernetes.io/proxy-connect-timeout` | Not supported yet. |
| `nginx.ingress.kubernetes.io/proxy-send-timeout` | Not supported. | | `nginx.ingress.kubernetes.io/proxy-send-timeout` | Not supported yet. |
| `nginx.ingress.kubernetes.io/proxy-read-timeout` | Not supported. | | `nginx.ingress.kubernetes.io/proxy-read-timeout` | Not supported yet. |
| `nginx.ingress.kubernetes.io/proxy-next-upstream` | Not supported. | | `nginx.ingress.kubernetes.io/proxy-next-upstream` | Not supported yet. |
| `nginx.ingress.kubernetes.io/proxy-next-upstream-timeout` | Not supported. | | `nginx.ingress.kubernetes.io/proxy-next-upstream-timeout` | Not supported yet. |
| `nginx.ingress.kubernetes.io/proxy-next-upstream-tries` | Not supported. | | `nginx.ingress.kubernetes.io/proxy-next-upstream-tries` | Not supported yet. |
| `nginx.ingress.kubernetes.io/proxy-request-buffering` | Not supported. | | `nginx.ingress.kubernetes.io/proxy-request-buffering` | Not supported yet. |
| `nginx.ingress.kubernetes.io/proxy-redirect-from` | Not supported. | | `nginx.ingress.kubernetes.io/proxy-redirect-from` | Not supported yet. |
| `nginx.ingress.kubernetes.io/proxy-redirect-to` | Not supported. | | `nginx.ingress.kubernetes.io/proxy-redirect-to` | Not supported yet. |
| `nginx.ingress.kubernetes.io/proxy-http-version` | Not supported. | | `nginx.ingress.kubernetes.io/proxy-http-version` | Not supported yet. |
| `nginx.ingress.kubernetes.io/proxy-ssl-ciphers` | Not supported. | | `nginx.ingress.kubernetes.io/proxy-ssl-ciphers` | Not supported yet. |
| `nginx.ingress.kubernetes.io/proxy-ssl-verify-depth` | Not supported. | | `nginx.ingress.kubernetes.io/proxy-ssl-verify-depth` | Not supported yet. |
| `nginx.ingress.kubernetes.io/proxy-ssl-protocols` | Not supported. | | `nginx.ingress.kubernetes.io/proxy-ssl-protocols` | Not supported yet. |
| `nginx.ingress.kubernetes.io/enable-rewrite-log` | Not supported. | | `nginx.ingress.kubernetes.io/enable-rewrite-log` | Not supported yet. |
| `nginx.ingress.kubernetes.io/rewrite-target` | Not supported. | | `nginx.ingress.kubernetes.io/rewrite-target` | Not supported yet. |
| `nginx.ingress.kubernetes.io/satisfy` | Not supported. | | `nginx.ingress.kubernetes.io/satisfy` | Not supported yet. |
| `nginx.ingress.kubernetes.io/server-alias` | Not supported. | | `nginx.ingress.kubernetes.io/server-alias` | Not supported yet. |
| `nginx.ingress.kubernetes.io/server-snippet` | Not supported. | | `nginx.ingress.kubernetes.io/server-snippet` | Not supported yet. |
| `nginx.ingress.kubernetes.io/session-cookie-conditional-samesite-none` | Not supported. | | `nginx.ingress.kubernetes.io/session-cookie-conditional-samesite-none` | Not supported yet. |
| `nginx.ingress.kubernetes.io/session-cookie-expires` | Not supported. | | `nginx.ingress.kubernetes.io/session-cookie-expires` | Not supported yet. |
| `nginx.ingress.kubernetes.io/session-cookie-change-on-failure` | Not supported. | | `nginx.ingress.kubernetes.io/session-cookie-change-on-failure` | Not supported yet. |
| `nginx.ingress.kubernetes.io/ssl-ciphers` | Not supported. | | `nginx.ingress.kubernetes.io/ssl-ciphers` | Not supported yet. |
| `nginx.ingress.kubernetes.io/ssl-prefer-server-ciphers` | Not supported. | | `nginx.ingress.kubernetes.io/ssl-prefer-server-ciphers` | Not supported yet. |
| `nginx.ingress.kubernetes.io/connection-proxy-header` | Not supported. | | `nginx.ingress.kubernetes.io/connection-proxy-header` | Not supported yet. |
| `nginx.ingress.kubernetes.io/enable-access-log` | Not supported. | | `nginx.ingress.kubernetes.io/enable-access-log` | Not supported yet. |
| `nginx.ingress.kubernetes.io/enable-opentracing` | Not supported. | | `nginx.ingress.kubernetes.io/enable-opentracing` | Not supported yet. |
| `nginx.ingress.kubernetes.io/opentracing-trust-incoming-span` | Not supported. | | `nginx.ingress.kubernetes.io/opentracing-trust-incoming-span` | Not supported yet. |
| `nginx.ingress.kubernetes.io/enable-opentelemetry` | Not supported. | | `nginx.ingress.kubernetes.io/enable-opentelemetry` | Not supported yet. |
| `nginx.ingress.kubernetes.io/opentelemetry-trust-incoming-span` | Not supported. | | `nginx.ingress.kubernetes.io/opentelemetry-trust-incoming-span` | Not supported yet. |
| `nginx.ingress.kubernetes.io/enable-modsecurity` | Not supported. | | `nginx.ingress.kubernetes.io/enable-modsecurity` | Not supported yet. |
| `nginx.ingress.kubernetes.io/enable-owasp-core-rules` | Not supported. | | `nginx.ingress.kubernetes.io/enable-owasp-core-rules` | Not supported yet. |
| `nginx.ingress.kubernetes.io/modsecurity-transaction-id` | Not supported. | | `nginx.ingress.kubernetes.io/modsecurity-transaction-id` | Not supported yet. |
| `nginx.ingress.kubernetes.io/modsecurity-snippet` | Not supported. | | `nginx.ingress.kubernetes.io/modsecurity-snippet` | Not supported yet. |
| `nginx.ingress.kubernetes.io/mirror-request-body` | Not supported. | | `nginx.ingress.kubernetes.io/mirror-request-body` | Not supported yet. |
| `nginx.ingress.kubernetes.io/mirror-target` | Not supported. | | `nginx.ingress.kubernetes.io/mirror-target` | Not supported yet. |
| `nginx.ingress.kubernetes.io/mirror-host` | Not supported. | | `nginx.ingress.kubernetes.io/mirror-host` | Not supported yet. |
| `nginx.ingress.kubernetes.io/x-forwarded-prefix` | Not supported. | | `nginx.ingress.kubernetes.io/x-forwarded-prefix` | Not supported yet. |
| `nginx.ingress.kubernetes.io/upstream-hash-by` | Not supported. | | `nginx.ingress.kubernetes.io/upstream-hash-by` | Not supported yet. |
| `nginx.ingress.kubernetes.io/upstream-vhost` | Not supported. | | `nginx.ingress.kubernetes.io/upstream-vhost` | Not supported yet. |
| `nginx.ingress.kubernetes.io/denylist-source-range` | Not supported. | | `nginx.ingress.kubernetes.io/denylist-source-range` | Not supported yet. |
| `nginx.ingress.kubernetes.io/whitelist-source-range` | Not supported. | | `nginx.ingress.kubernetes.io/whitelist-source-range` | Not supported yet. |
| `nginx.ingress.kubernetes.io/proxy-buffering` | Not supported. | | `nginx.ingress.kubernetes.io/proxy-buffering` | Not supported yet. |
| `nginx.ingress.kubernetes.io/proxy-buffers-number` | Not supported. | | `nginx.ingress.kubernetes.io/proxy-buffers-number` | Not supported yet. |
| `nginx.ingress.kubernetes.io/proxy-buffer-size` | Not supported. | | `nginx.ingress.kubernetes.io/proxy-buffer-size` | Not supported yet. |
| `nginx.ingress.kubernetes.io/proxy-max-temp-file-size` | Not supported. | | `nginx.ingress.kubernetes.io/proxy-max-temp-file-size` | Not supported yet. |
| `nginx.ingress.kubernetes.io/stream-snippet` | Not supported. | | `nginx.ingress.kubernetes.io/stream-snippet` | Not supported yet. |

View File

@ -91,7 +91,7 @@ TLS key
Defines additional resource attributes (key:value). Defines additional resource attributes (key:value).
`--accesslog.otlp.servicename`: `--accesslog.otlp.servicename`:
Set the name for this service. (Default: ```traefik```) Defines the service name resource attribute. (Default: ```traefik```)
`--api`: `--api`:
Enable api/dashboard. (Default: ```false```) Enable api/dashboard. (Default: ```false```)
@ -283,13 +283,16 @@ HTTP/3 configuration. (Default: ```false```)
UDP port to advertise, on which HTTP/3 is available. (Default: ```0```) UDP port to advertise, on which HTTP/3 is available. (Default: ```0```)
`--entrypoints.<name>.observability.accesslogs`: `--entrypoints.<name>.observability.accesslogs`:
(Default: ```true```) Enables access-logs for this entryPoint. (Default: ```true```)
`--entrypoints.<name>.observability.metrics`: `--entrypoints.<name>.observability.metrics`:
(Default: ```true```) Enables metrics for this entryPoint. (Default: ```true```)
`--entrypoints.<name>.observability.traceverbosity`:
Defines the tracing verbosity level for this entryPoint. (Default: ```minimal```)
`--entrypoints.<name>.observability.tracing`: `--entrypoints.<name>.observability.tracing`:
(Default: ```true```) Enables tracing for this entryPoint. (Default: ```true```)
`--entrypoints.<name>.proxyprotocol`: `--entrypoints.<name>.proxyprotocol`:
Proxy-Protocol configuration. (Default: ```false```) Proxy-Protocol configuration. (Default: ```false```)
@ -478,7 +481,7 @@ TLS key
Defines additional resource attributes (key:value). Defines additional resource attributes (key:value).
`--log.otlp.servicename`: `--log.otlp.servicename`:
Set the name for this service. (Default: ```traefik```) Defines the service name resource attribute. (Default: ```traefik```)
`--metrics.addinternals`: `--metrics.addinternals`:
Enables metrics for internal services (ping, dashboard, etc...). (Default: ```false```) Enables metrics for internal services (ping, dashboard, etc...). (Default: ```false```)
@ -597,8 +600,11 @@ TLS key
`--metrics.otlp.pushinterval`: `--metrics.otlp.pushinterval`:
Period between calls to collect a checkpoint. (Default: ```10```) Period between calls to collect a checkpoint. (Default: ```10```)
`--metrics.otlp.resourceattributes.<name>`:
Defines additional resource attributes (key:value).
`--metrics.otlp.servicename`: `--metrics.otlp.servicename`:
OTEL service name to use. (Default: ```traefik```) Defines the service name resource attribute. (Default: ```traefik```)
`--metrics.prometheus`: `--metrics.prometheus`:
Prometheus metrics exporter type. (Default: ```false```) Prometheus metrics exporter type. (Default: ```false```)
@ -1411,4 +1417,4 @@ Query params to not redact.
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```)
`--tracing.servicename`: `--tracing.servicename`:
Sets the name for this service. (Default: ```traefik```) Defines the service name resource attribute. (Default: ```traefik```)

View File

@ -91,7 +91,7 @@ TLS key
Defines additional resource attributes (key:value). Defines additional resource attributes (key:value).
`TRAEFIK_ACCESSLOG_OTLP_SERVICENAME`: `TRAEFIK_ACCESSLOG_OTLP_SERVICENAME`:
Set the name for this service. (Default: ```traefik```) Defines the service name resource attribute. (Default: ```traefik```)
`TRAEFIK_API`: `TRAEFIK_API`:
Enable api/dashboard. (Default: ```false```) Enable api/dashboard. (Default: ```false```)
@ -283,13 +283,16 @@ Subject alternative names.
Default TLS options for the routers linked to the entry point. Default TLS options for the routers linked to the entry point.
`TRAEFIK_ENTRYPOINTS_<NAME>_OBSERVABILITY_ACCESSLOGS`: `TRAEFIK_ENTRYPOINTS_<NAME>_OBSERVABILITY_ACCESSLOGS`:
(Default: ```true```) Enables access-logs for this entryPoint. (Default: ```true```)
`TRAEFIK_ENTRYPOINTS_<NAME>_OBSERVABILITY_METRICS`: `TRAEFIK_ENTRYPOINTS_<NAME>_OBSERVABILITY_METRICS`:
(Default: ```true```) Enables metrics for this entryPoint. (Default: ```true```)
`TRAEFIK_ENTRYPOINTS_<NAME>_OBSERVABILITY_TRACEVERBOSITY`:
Defines the tracing verbosity level for this entryPoint. (Default: ```minimal```)
`TRAEFIK_ENTRYPOINTS_<NAME>_OBSERVABILITY_TRACING`: `TRAEFIK_ENTRYPOINTS_<NAME>_OBSERVABILITY_TRACING`:
(Default: ```true```) Enables tracing for this entryPoint. (Default: ```true```)
`TRAEFIK_ENTRYPOINTS_<NAME>_PROXYPROTOCOL`: `TRAEFIK_ENTRYPOINTS_<NAME>_PROXYPROTOCOL`:
Proxy-Protocol configuration. (Default: ```false```) Proxy-Protocol configuration. (Default: ```false```)
@ -478,7 +481,7 @@ TLS key
Defines additional resource attributes (key:value). Defines additional resource attributes (key:value).
`TRAEFIK_LOG_OTLP_SERVICENAME`: `TRAEFIK_LOG_OTLP_SERVICENAME`:
Set the name for this service. (Default: ```traefik```) Defines the service name resource attribute. (Default: ```traefik```)
`TRAEFIK_METRICS_ADDINTERNALS`: `TRAEFIK_METRICS_ADDINTERNALS`:
Enables metrics for internal services (ping, dashboard, etc...). (Default: ```false```) Enables metrics for internal services (ping, dashboard, etc...). (Default: ```false```)
@ -597,8 +600,11 @@ TLS key
`TRAEFIK_METRICS_OTLP_PUSHINTERVAL`: `TRAEFIK_METRICS_OTLP_PUSHINTERVAL`:
Period between calls to collect a checkpoint. (Default: ```10```) Period between calls to collect a checkpoint. (Default: ```10```)
`TRAEFIK_METRICS_OTLP_RESOURCEATTRIBUTES_<NAME>`:
Defines additional resource attributes (key:value).
`TRAEFIK_METRICS_OTLP_SERVICENAME`: `TRAEFIK_METRICS_OTLP_SERVICENAME`:
OTEL service name to use. (Default: ```traefik```) Defines the service name resource attribute. (Default: ```traefik```)
`TRAEFIK_METRICS_PROMETHEUS`: `TRAEFIK_METRICS_PROMETHEUS`:
Prometheus metrics exporter type. (Default: ```false```) Prometheus metrics exporter type. (Default: ```false```)
@ -1411,4 +1417,4 @@ Query params to not redact.
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```)
`TRAEFIK_TRACING_SERVICENAME`: `TRAEFIK_TRACING_SERVICENAME`:
Sets the name for this service. (Default: ```traefik```) Defines the service name resource attribute. (Default: ```traefik```)

View File

@ -80,8 +80,9 @@
timeout = "42s" timeout = "42s"
[entryPoints.EntryPoint0.observability] [entryPoints.EntryPoint0.observability]
accessLogs = true accessLogs = true
tracing = true
metrics = true metrics = true
tracing = true
traceVerbosity = "foobar"
[providers] [providers]
providersThrottleDuration = "42s" providersThrottleDuration = "42s"
@ -387,6 +388,9 @@
[metrics.otlp.http.headers] [metrics.otlp.http.headers]
name0 = "foobar" name0 = "foobar"
name1 = "foobar" name1 = "foobar"
[metrics.otlp.resourceAttributes]
name0 = "foobar"
name1 = "foobar"
[ping] [ping]
entryPoint = "foobar" entryPoint = "foobar"

View File

@ -94,8 +94,9 @@ entryPoints:
timeout: 42s timeout: 42s
observability: observability:
accessLogs: true accessLogs: true
tracing: true
metrics: true metrics: true
tracing: true
traceVerbosity: foobar
providers: providers:
providersThrottleDuration: 42s providersThrottleDuration: 42s
docker: docker:
@ -428,6 +429,9 @@ metrics:
- 42 - 42
pushInterval: 42s pushInterval: 42s
serviceName: foobar serviceName: foobar
resourceAttributes:
name0: foobar
name1: foobar
ping: ping:
entryPoint: foobar entryPoint: foobar
manualRouting: true manualRouting: true

View File

@ -1671,7 +1671,7 @@ or referencing TLS options in the [`IngressRoute`](#kind-ingressroute) / [`Ingre
| [2] | `minVersion` | Defines the [minimum TLS version](../../https/tls.md#minimum-tls-version) that is acceptable. | | [2] | `minVersion` | Defines the [minimum TLS version](../../https/tls.md#minimum-tls-version) that is acceptable. |
| [3] | `maxVersion` | Defines the [maximum TLS version](../../https/tls.md#maximum-tls-version) that is acceptable. | | [3] | `maxVersion` | Defines the [maximum TLS version](../../https/tls.md#maximum-tls-version) that is acceptable. |
| [4] | `cipherSuites` | list of supported [cipher suites](../../https/tls.md#cipher-suites) for TLS versions up to TLS 1.2. | | [4] | `cipherSuites` | list of supported [cipher suites](../../https/tls.md#cipher-suites) for TLS versions up to TLS 1.2. |
| [5] | `curvePreferences` | List of the [elliptic curves references](../../https/tls.md#curve-preferences) that will be used in an ECDHE handshake, in preference order. | | [5] | `curvePreferences` | List of the [elliptic curves references](../../https/tls.md#curve-preferences) that will be used in an ECDHE handshake. |
| [6] | `clientAuth` | determines the server's policy for TLS [Client Authentication](../../https/tls.md#client-authentication-mtls). | | [6] | `clientAuth` | determines the server's policy for TLS [Client Authentication](../../https/tls.md#client-authentication-mtls). |
| [7] | `clientAuth.secretNames` | list of names of the referenced Kubernetes [Secrets](https://kubernetes.io/docs/concepts/configuration/secret/) (in TLSOption namespace). The secret must contain a certificate under either a `tls.ca` or a `ca.crt` key. | | [7] | `clientAuth.secretNames` | list of names of the referenced Kubernetes [Secrets](https://kubernetes.io/docs/concepts/configuration/secret/) (in TLSOption namespace). The secret must contain a certificate under either a `tls.ca` or a `ca.crt` key. |
| [8] | `clientAuth.clientAuthType` | defines the client authentication type to apply. The available values are: `NoClientCert`, `RequestClientCert`, `VerifyClientCertIfGiven` and `RequireAndVerifyClientCert`. | | [8] | `clientAuth.clientAuthType` | defines the client authentication type to apply. The available values are: `NoClientCert`, `RequestClientCert`, `VerifyClientCertIfGiven` and `RequireAndVerifyClientCert`. |

5
go.mod
View File

@ -55,7 +55,7 @@ require (
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // No tag on the repo. github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // No tag on the repo.
github.com/prometheus/client_golang v1.19.1 github.com/prometheus/client_golang v1.19.1
github.com/prometheus/client_model v0.6.1 github.com/prometheus/client_model v0.6.1
github.com/quic-go/quic-go v0.49.0 github.com/quic-go/quic-go v0.54.0
github.com/redis/go-redis/v9 v9.7.3 github.com/redis/go-redis/v9 v9.7.3
github.com/rs/zerolog v1.33.0 github.com/rs/zerolog v1.33.0
github.com/sirupsen/logrus v1.9.3 github.com/sirupsen/logrus v1.9.3
@ -206,7 +206,6 @@ require (
github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.16.0 // indirect github.com/go-playground/validator/v10 v10.16.0 // indirect
github.com/go-resty/resty/v2 v2.16.5 // indirect github.com/go-resty/resty/v2 v2.16.5 // indirect
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/go-viper/mapstructure/v2 v2.3.0 // indirect github.com/go-viper/mapstructure/v2 v2.3.0 // indirect
github.com/go-zookeeper/zk v1.0.3 // indirect github.com/go-zookeeper/zk v1.0.3 // indirect
github.com/goccy/go-json v0.10.5 // indirect github.com/goccy/go-json v0.10.5 // indirect
@ -218,7 +217,6 @@ require (
github.com/google/go-cmp v0.7.0 // indirect github.com/google/go-cmp v0.7.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-querystring v1.1.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect github.com/google/gofuzz v1.2.0 // indirect
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db // indirect
github.com/google/s2a-go v0.1.9 // indirect github.com/google/s2a-go v0.1.9 // indirect
github.com/google/uuid v1.6.0 // indirect github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
@ -293,7 +291,6 @@ require (
github.com/nrdcg/porkbun v0.4.0 // indirect github.com/nrdcg/porkbun v0.4.0 // indirect
github.com/nzdjb/go-metaname v1.0.0 // indirect github.com/nzdjb/go-metaname v1.0.0 // indirect
github.com/onsi/ginkgo v1.16.5 // indirect github.com/onsi/ginkgo v1.16.5 // indirect
github.com/onsi/ginkgo/v2 v2.22.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0 // indirect github.com/opencontainers/image-spec v1.1.0 // indirect
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect

5
go.sum
View File

@ -421,6 +421,7 @@ github.com/go-resty/resty/v2 v2.16.5 h1:hBKqmWrr7uRc3euHVqmh1HTHcKn99Smr7o5spptd
github.com/go-resty/resty/v2 v2.16.5/go.mod h1:hkJtXbA2iKHzJheXYvQ8snQES5ZLGKMwQ07xAwp/fiA= github.com/go-resty/resty/v2 v2.16.5/go.mod h1:hkJtXbA2iKHzJheXYvQ8snQES5ZLGKMwQ07xAwp/fiA=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/go-viper/mapstructure/v2 v2.3.0 h1:27XbWsHIqhbdR5TIC911OfYvgSaW93HM+dX7970Q7jk= github.com/go-viper/mapstructure/v2 v2.3.0 h1:27XbWsHIqhbdR5TIC911OfYvgSaW93HM+dX7970Q7jk=
@ -1033,8 +1034,8 @@ github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoG
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
github.com/quic-go/quic-go v0.49.0 h1:w5iJHXwHxs1QxyBv1EHKuC50GX5to8mJAxvtnttJp94= github.com/quic-go/quic-go v0.54.0 h1:6s1YB9QotYI6Ospeiguknbp2Znb/jZYjZLRXn9kMQBg=
github.com/quic-go/quic-go v0.49.0/go.mod h1:s2wDnmCdooUQBmQfpUSTCYBl1/D4FcqbULMMkASvR6s= github.com/quic-go/quic-go v0.54.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM= github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM=

View File

@ -648,25 +648,6 @@ func (s *AccessLogSuite) TestAccessLogDisabledForInternals() {
require.Equal(s.T(), 0, count) require.Equal(s.T(), 0, count)
// Make some requests on the custom ping router in error.
req, err = http.NewRequest(http.MethodGet, "http://127.0.0.1:8010/ping-error", nil)
require.NoError(s.T(), err)
req.Host = "ping-error.docker.local"
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusUnauthorized), try.BodyContains("X-Forwarded-Host: ping-error.docker.local"))
require.NoError(s.T(), err)
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusUnauthorized), try.BodyContains("X-Forwarded-Host: ping-error.docker.local"))
require.NoError(s.T(), err)
// Here we verify that the remove of observability doesn't break the metrics for the error page service.
req, err = http.NewRequest(http.MethodGet, "http://127.0.0.1:8080/metrics", nil)
require.NoError(s.T(), err)
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK), try.BodyContains("service3"))
require.NoError(s.T(), err)
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK), try.BodyNotContains("service=\"ping"))
require.NoError(s.T(), err)
// Verify no other Traefik problems. // Verify no other Traefik problems.
s.checkNoOtherTraefikProblems() s.checkNoOtherTraefikProblems()
} }

View File

@ -92,10 +92,21 @@ spec:
More info: https://doc.traefik.io/traefik/v3.5/routing/routers/#observability More info: https://doc.traefik.io/traefik/v3.5/routing/routers/#observability
properties: properties:
accessLogs: accessLogs:
description: AccessLogs enables access logs for this router.
type: boolean type: boolean
metrics: metrics:
description: Metrics enables metrics for this router.
type: boolean type: boolean
traceVerbosity:
default: minimal
description: TraceVerbosity defines the verbosity level
of the tracing for this router.
enum:
- minimal
- detailed
type: string
tracing: tracing:
description: Tracing enables tracing for this router.
type: boolean type: boolean
type: object type: object
priority: priority:
@ -2551,7 +2562,7 @@ spec:
type: object type: object
curvePreferences: curvePreferences:
description: |- description: |-
CurvePreferences defines the preferred elliptic curves in a specific order. CurvePreferences defines the preferred elliptic curves.
More info: https://doc.traefik.io/traefik/v3.5/https/tls/#curve-preferences More info: https://doc.traefik.io/traefik/v3.5/https/tls/#curve-preferences
items: items:
type: string type: string

View File

@ -14,6 +14,10 @@
[entryPoints] [entryPoints]
[entryPoints.web] [entryPoints.web]
address = ":8000" address = ":8000"
[entryPoints.web.observability]
traceVerbosity = "detailed"
[entryPoints.web-minimal]
address = ":8001"
# Adding metrics to confirm that there is no wrong interaction with tracing. # Adding metrics to confirm that there is no wrong interaction with tracing.
[metrics] [metrics]
@ -44,9 +48,13 @@
## dynamic configuration ## ## dynamic configuration ##
[http.routers] [http.routers]
[http.routers.routerBasicMinimal]
Service = "service0"
Rule = "Path(`/basic-minimal`)"
[http.routers.routerBasicMinimal.observability]
traceVerbosity = "minimal"
[http.routers.router0] [http.routers.router0]
Service = "service0" Service = "service0"
Middlewares = []
Rule = "Path(`/basic`)" Rule = "Path(`/basic`)"
[http.routers.router1] [http.routers.router1]
Service = "service1" Service = "service1"

View File

@ -101,13 +101,3 @@ services:
traefik.http.routers.ping.entryPoints: ping traefik.http.routers.ping.entryPoints: ping
traefik.http.routers.ping.rule: PathPrefix(`/ping`) traefik.http.routers.ping.rule: PathPrefix(`/ping`)
traefik.http.routers.ping.service: ping@internal traefik.http.routers.ping.service: ping@internal
traefik.http.routers.ping-error.entryPoints: ping
traefik.http.routers.ping-error.rule: PathPrefix(`/ping-error`)
traefik.http.routers.ping-error.middlewares: errors, basicauth
traefik.http.routers.ping-error.service: ping@internal
traefik.http.middlewares.basicauth.basicauth.users: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"
traefik.http.middlewares.errors.errors.status: 401
traefik.http.middlewares.errors.errors.service: service3
traefik.http.middlewares.errors.errors.query: /
traefik.http.services.service3.loadbalancer.server.port: 80

View File

@ -14,8 +14,9 @@
"tls": {}, "tls": {},
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [
@ -49,8 +50,9 @@
}, },
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [
@ -67,8 +69,9 @@
"priority": 9223372036854775806, "priority": 9223372036854775806,
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [
@ -89,8 +92,9 @@
"priority": 9223372036854775805, "priority": 9223372036854775805,
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [
@ -100,7 +104,13 @@
}, },
"middlewares": { "middlewares": {
"compressor@consul": { "compressor@consul": {
"compress": {}, "compress": {
"encodings": [
"gzip",
"br",
"zstd"
]
},
"status": "enabled", "status": "enabled",
"usedBy": [ "usedBy": [
"Router0@consul" "Router0@consul"
@ -173,6 +183,7 @@
"mirror@consul": { "mirror@consul": {
"mirroring": { "mirroring": {
"service": "simplesvc", "service": "simplesvc",
"mirrorBody": true,
"maxBodySize": -1, "maxBodySize": -1,
"mirrors": [ "mirrors": [
{ {

View File

@ -9,8 +9,9 @@
"priority": 18, "priority": 18,
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [
@ -29,8 +30,9 @@
}, },
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [

View File

@ -9,8 +9,9 @@
"priority": 18, "priority": 18,
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [
@ -29,8 +30,9 @@
}, },
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [
@ -49,8 +51,9 @@
"priority": 46, "priority": 46,
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [
@ -66,8 +69,9 @@
"priority": 38, "priority": 38,
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [
@ -83,8 +87,9 @@
"priority": 50, "priority": 50,
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [
@ -100,8 +105,9 @@
"priority": 35, "priority": 35,
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"error": [ "error": [
"the service \"other-ns-wrr3@kubernetescrd\" does not exist" "the service \"other-ns-wrr3@kubernetescrd\" does not exist"

View File

@ -14,8 +14,9 @@
"tls": {}, "tls": {},
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [
@ -49,8 +50,9 @@
}, },
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [
@ -67,8 +69,9 @@
"priority": 9223372036854775806, "priority": 9223372036854775806,
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [
@ -89,8 +92,9 @@
"priority": 9223372036854775805, "priority": 9223372036854775805,
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [
@ -100,7 +104,13 @@
}, },
"middlewares": { "middlewares": {
"compressor@etcd": { "compressor@etcd": {
"compress": {}, "compress": {
"encodings": [
"gzip",
"br",
"zstd"
]
},
"status": "enabled", "status": "enabled",
"usedBy": [ "usedBy": [
"Router0@etcd" "Router0@etcd"
@ -173,6 +183,7 @@
"mirror@etcd": { "mirror@etcd": {
"mirroring": { "mirroring": {
"service": "simplesvc", "service": "simplesvc",
"mirrorBody": true,
"maxBodySize": -1, "maxBodySize": -1,
"mirrors": [ "mirrors": [
{ {

View File

@ -10,8 +10,9 @@
"priority": 9223372036854775806, "priority": 9223372036854775806,
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [
@ -32,8 +33,9 @@
"priority": 9223372036854775805, "priority": 9223372036854775805,
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [
@ -50,8 +52,9 @@
"priority": 100008, "priority": 100008,
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [
@ -69,8 +72,9 @@
"tls": {}, "tls": {},
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [

View File

@ -10,8 +10,9 @@
"priority": 9223372036854775806, "priority": 9223372036854775806,
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [
@ -32,8 +33,9 @@
"priority": 9223372036854775805, "priority": 9223372036854775805,
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [
@ -49,8 +51,9 @@
"priority": 44, "priority": 44,
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [

View File

@ -10,8 +10,9 @@
"priority": 9223372036854775806, "priority": 9223372036854775806,
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [
@ -32,8 +33,9 @@
"priority": 9223372036854775805, "priority": 9223372036854775805,
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [
@ -49,8 +51,9 @@
"priority": 50, "priority": 50,
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [
@ -66,8 +69,9 @@
"priority": 44, "priority": 44,
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [
@ -83,8 +87,9 @@
"priority": 47, "priority": 47,
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [
@ -100,8 +105,9 @@
"priority": 47, "priority": 47,
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [

View File

@ -10,8 +10,9 @@
"priority": 9223372036854775806, "priority": 9223372036854775806,
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [
@ -32,8 +33,9 @@
"priority": 9223372036854775805, "priority": 9223372036854775805,
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [

View File

@ -10,8 +10,9 @@
"priority": 9223372036854775806, "priority": 9223372036854775806,
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [
@ -32,8 +33,9 @@
"priority": 9223372036854775805, "priority": 9223372036854775805,
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [
@ -49,8 +51,9 @@
"priority": 47, "priority": 47,
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [

View File

@ -14,8 +14,9 @@
"tls": {}, "tls": {},
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [
@ -49,8 +50,9 @@
}, },
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [
@ -67,8 +69,9 @@
"priority": 9223372036854775806, "priority": 9223372036854775806,
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [
@ -89,8 +92,9 @@
"priority": 9223372036854775805, "priority": 9223372036854775805,
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [
@ -100,7 +104,13 @@
}, },
"middlewares": { "middlewares": {
"compressor@redis": { "compressor@redis": {
"compress": {}, "compress": {
"encodings": [
"gzip",
"br",
"zstd"
]
},
"status": "enabled", "status": "enabled",
"usedBy": [ "usedBy": [
"Router0@redis" "Router0@redis"
@ -173,6 +183,7 @@
"mirror@redis": { "mirror@redis": {
"mirroring": { "mirroring": {
"service": "simplesvc", "service": "simplesvc",
"mirrorBody": true,
"maxBodySize": -1, "maxBodySize": -1,
"mirrors": [ "mirrors": [
{ {
@ -244,6 +255,7 @@
"url": "http://10.0.1.3:8889" "url": "http://10.0.1.3:8889"
} }
], ],
"strategy": "wrr",
"passHostHeader": true, "passHostHeader": true,
"responseForwarding": { "responseForwarding": {
"flushInterval": "100ms" "flushInterval": "100ms"

View File

@ -14,8 +14,9 @@
"tls": {}, "tls": {},
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [
@ -49,8 +50,9 @@
}, },
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [
@ -67,8 +69,9 @@
"priority": 9223372036854775806, "priority": 9223372036854775806,
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [
@ -89,8 +92,9 @@
"priority": 9223372036854775805, "priority": 9223372036854775805,
"observability": { "observability": {
"accessLogs": true, "accessLogs": true,
"metrics": true,
"tracing": true, "tracing": true,
"metrics": true "traceVerbosity": "minimal"
}, },
"status": "enabled", "status": "enabled",
"using": [ "using": [
@ -100,7 +104,13 @@
}, },
"middlewares": { "middlewares": {
"compressor@zookeeper": { "compressor@zookeeper": {
"compress": {}, "compress": {
"encodings": [
"gzip",
"br",
"zstd"
]
},
"status": "enabled", "status": "enabled",
"usedBy": [ "usedBy": [
"Router0@zookeeper" "Router0@zookeeper"
@ -173,6 +183,7 @@
"mirror@zookeeper": { "mirror@zookeeper": {
"mirroring": { "mirroring": {
"service": "simplesvc", "service": "simplesvc",
"mirrorBody": true,
"maxBodySize": -1, "maxBodySize": -1,
"mirrors": [ "mirrors": [
{ {

View File

@ -77,6 +77,104 @@ func (s *TracingSuite) TearDownTest() {
s.composeStop("tempo") s.composeStop("tempo")
} }
func (s *TracingSuite) TestOpenTelemetryBasic_HTTP_router_minimalVerbosity() {
file := s.adaptFile("fixtures/tracing/simple-opentelemetry.toml", TracingTemplate{
WhoamiIP: s.whoamiIP,
WhoamiPort: s.whoamiPort,
IP: s.otelCollectorIP,
IsHTTP: true,
})
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://127.0.0.1:8000/basic-minimal", 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.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=\"network.protocol.version\").value.stringValue": "1.1",
"batches.0.scopeSpans.0.spans.0.attributes.#(key=\"url.full\").value.stringValue": fmt.Sprintf("http://%s/basic-minimal", 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": "EntryPoint",
"batches.0.scopeSpans.0.spans.1.kind": "SPAN_KIND_SERVER",
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"entry_point\").value.stringValue": "web",
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"http.request.method\").value.stringValue": "GET",
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"url.path\").value.stringValue": "/basic-minimal",
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"url.query\").value.stringValue": "",
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1",
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"server.address\").value.stringValue": "127.0.0.1:8000",
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"network.peer.address\").value.stringValue": "127.0.0.1",
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"http.response.status_code\").value.intValue": "200",
},
}
s.checkTraceContent(contains)
}
func (s *TracingSuite) TestOpenTelemetryBasic_HTTP_entrypoint_minimalVerbosity() {
file := s.adaptFile("fixtures/tracing/simple-opentelemetry.toml", TracingTemplate{
WhoamiIP: s.whoamiIP,
WhoamiPort: s.whoamiPort,
IP: s.otelCollectorIP,
IsHTTP: true,
})
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://127.0.0.1:8001/basic", 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.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=\"network.protocol.version\").value.stringValue": "1.1",
"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.1.name": "EntryPoint",
"batches.0.scopeSpans.0.spans.1.kind": "SPAN_KIND_SERVER",
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"entry_point\").value.stringValue": "web-minimal",
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"http.request.method\").value.stringValue": "GET",
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"url.path\").value.stringValue": "/basic",
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"url.query\").value.stringValue": "",
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1",
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"server.address\").value.stringValue": "127.0.0.1:8001",
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"network.peer.address\").value.stringValue": "127.0.0.1",
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"http.response.status_code\").value.intValue": "200",
},
}
s.checkTraceContent(contains)
}
func (s *TracingSuite) TestOpenTelemetryBasic_HTTP() { func (s *TracingSuite) TestOpenTelemetryBasic_HTTP() {
file := s.adaptFile("fixtures/tracing/simple-opentelemetry.toml", TracingTemplate{ file := s.adaptFile("fixtures/tracing/simple-opentelemetry.toml", TracingTemplate{
WhoamiIP: s.whoamiIP, WhoamiIP: s.whoamiIP,
@ -121,7 +219,7 @@ func (s *TracingSuite) TestOpenTelemetryBasic_HTTP() {
"batches.0.scopeSpans.0.spans.3.name": "Router", "batches.0.scopeSpans.0.spans.3.name": "Router",
"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": "service0@file", "batches.0.scopeSpans.0.spans.3.attributes.#(key=\"traefik.service.name\").value.stringValue": "service0@file",
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"traefik.router.name\").value.stringValue": "router0@file", "batches.0.scopeSpans.0.spans.3.attributes.#(key=\"traefik.router.name\").value.stringValue": "web-router0@file",
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"http.route\").value.stringValue": "Path(`/basic`)", "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.name": "Metrics",
@ -189,7 +287,7 @@ func (s *TracingSuite) TestOpenTelemetryBasic_gRPC() {
"batches.0.scopeSpans.0.spans.3.name": "Router", "batches.0.scopeSpans.0.spans.3.name": "Router",
"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": "service0@file", "batches.0.scopeSpans.0.spans.3.attributes.#(key=\"traefik.service.name\").value.stringValue": "service0@file",
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"traefik.router.name\").value.stringValue": "router0@file", "batches.0.scopeSpans.0.spans.3.attributes.#(key=\"traefik.router.name\").value.stringValue": "web-router0@file",
"batches.0.scopeSpans.0.spans.3.attributes.#(key=\"http.route\").value.stringValue": "Path(`/basic`)", "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.name": "Metrics",
@ -251,7 +349,7 @@ func (s *TracingSuite) TestOpenTelemetryRateLimit() {
"batches.0.scopeSpans.0.spans.1.name": "Router", "batches.0.scopeSpans.0.spans.1.name": "Router",
"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": "service1@file", "batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.service.name\").value.stringValue": "service1@file",
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.router.name\").value.stringValue": "router1@file", "batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.router.name\").value.stringValue": "web-router1@file",
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"http.route\").value.stringValue": "Path(`/ratelimit`)", "batches.0.scopeSpans.0.spans.1.attributes.#(key=\"http.route\").value.stringValue": "Path(`/ratelimit`)",
"batches.0.scopeSpans.0.spans.2.name": "Metrics", "batches.0.scopeSpans.0.spans.2.name": "Metrics",
@ -299,7 +397,7 @@ func (s *TracingSuite) TestOpenTelemetryRateLimit() {
"batches.0.scopeSpans.0.spans.4.name": "Router", "batches.0.scopeSpans.0.spans.4.name": "Router",
"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.service.name\").value.stringValue": "service1@file",
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"traefik.router.name\").value.stringValue": "router1@file", "batches.0.scopeSpans.0.spans.4.attributes.#(key=\"traefik.router.name\").value.stringValue": "web-router1@file",
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"http.route\").value.stringValue": "Path(`/ratelimit`)", "batches.0.scopeSpans.0.spans.4.attributes.#(key=\"http.route\").value.stringValue": "Path(`/ratelimit`)",
"batches.0.scopeSpans.0.spans.5.name": "Metrics", "batches.0.scopeSpans.0.spans.5.name": "Metrics",
@ -423,7 +521,7 @@ func (s *TracingSuite) TestOpenTelemetryRetry() {
"batches.0.scopeSpans.0.spans.12.name": "Router", "batches.0.scopeSpans.0.spans.12.name": "Router",
"batches.0.scopeSpans.0.spans.12.kind": "SPAN_KIND_INTERNAL", "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.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.12.attributes.#(key=\"traefik.router.name\").value.stringValue": "web-router2@file",
"batches.0.scopeSpans.0.spans.13.name": "Metrics", "batches.0.scopeSpans.0.spans.13.name": "Metrics",
"batches.0.scopeSpans.0.spans.13.kind": "SPAN_KIND_INTERNAL", "batches.0.scopeSpans.0.spans.13.kind": "SPAN_KIND_INTERNAL",
@ -475,7 +573,7 @@ func (s *TracingSuite) TestOpenTelemetryAuth() {
"batches.0.scopeSpans.0.spans.1.name": "Router", "batches.0.scopeSpans.0.spans.1.name": "Router",
"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": "service3@file", "batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.service.name\").value.stringValue": "service3@file",
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.router.name\").value.stringValue": "router3@file", "batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.router.name\").value.stringValue": "web-router3@file",
"batches.0.scopeSpans.0.spans.1.attributes.#(key=\"http.route\").value.stringValue": "Path(`/auth`)", "batches.0.scopeSpans.0.spans.1.attributes.#(key=\"http.route\").value.stringValue": "Path(`/auth`)",
"batches.0.scopeSpans.0.spans.2.name": "Metrics", "batches.0.scopeSpans.0.spans.2.name": "Metrics",
@ -532,7 +630,7 @@ func (s *TracingSuite) TestOpenTelemetryAuthWithRetry() {
"batches.0.scopeSpans.0.spans.2.name": "Router", "batches.0.scopeSpans.0.spans.2.name": "Router",
"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": "service4@file", "batches.0.scopeSpans.0.spans.2.attributes.#(key=\"traefik.service.name\").value.stringValue": "service4@file",
"batches.0.scopeSpans.0.spans.2.attributes.#(key=\"traefik.router.name\").value.stringValue": "router4@file", "batches.0.scopeSpans.0.spans.2.attributes.#(key=\"traefik.router.name\").value.stringValue": "web-router4@file",
"batches.0.scopeSpans.0.spans.2.attributes.#(key=\"http.route\").value.stringValue": "Path(`/retry-auth`)", "batches.0.scopeSpans.0.spans.2.attributes.#(key=\"http.route\").value.stringValue": "Path(`/retry-auth`)",
"batches.0.scopeSpans.0.spans.3.name": "Metrics", "batches.0.scopeSpans.0.spans.3.name": "Metrics",
@ -601,7 +699,7 @@ func (s *TracingSuite) TestOpenTelemetrySafeURL() {
"batches.0.scopeSpans.0.spans.4.name": "Router", "batches.0.scopeSpans.0.spans.4.name": "Router",
"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": "service3@file", "batches.0.scopeSpans.0.spans.4.attributes.#(key=\"traefik.service.name\").value.stringValue": "service3@file",
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"traefik.router.name\").value.stringValue": "router3@file", "batches.0.scopeSpans.0.spans.4.attributes.#(key=\"traefik.router.name\").value.stringValue": "web-router3@file",
"batches.0.scopeSpans.0.spans.4.attributes.#(key=\"http.route\").value.stringValue": "Path(`/auth`)", "batches.0.scopeSpans.0.spans.4.attributes.#(key=\"http.route\").value.stringValue": "Path(`/auth`)",
"batches.0.scopeSpans.0.spans.5.name": "Metrics", "batches.0.scopeSpans.0.spans.5.name": "Metrics",

View File

@ -88,9 +88,21 @@ type RouterTLSConfig struct {
// RouterObservabilityConfig holds the observability configuration for a router. // RouterObservabilityConfig holds the observability configuration for a router.
type RouterObservabilityConfig struct { type RouterObservabilityConfig struct {
// AccessLogs enables access logs for this router.
AccessLogs *bool `json:"accessLogs,omitempty" toml:"accessLogs,omitempty" yaml:"accessLogs,omitempty" export:"true"` AccessLogs *bool `json:"accessLogs,omitempty" toml:"accessLogs,omitempty" yaml:"accessLogs,omitempty" export:"true"`
Tracing *bool `json:"tracing,omitempty" toml:"tracing,omitempty" yaml:"tracing,omitempty" export:"true"` // Metrics enables metrics for this router.
Metrics *bool `json:"metrics,omitempty" toml:"metrics,omitempty" yaml:"metrics,omitempty" export:"true"` Metrics *bool `json:"metrics,omitempty" toml:"metrics,omitempty" yaml:"metrics,omitempty" export:"true"`
// Tracing enables tracing for this router.
Tracing *bool `json:"tracing,omitempty" toml:"tracing,omitempty" yaml:"tracing,omitempty" export:"true"`
// TraceVerbosity defines the verbosity level of the tracing for this router.
// +kubebuilder:validation:Enum=minimal;detailed
// +kubebuilder:default=minimal
TraceVerbosity types.TracingVerbosity `json:"traceVerbosity,omitempty" toml:"traceVerbosity,omitempty" yaml:"traceVerbosity,omitempty" export:"true"`
}
// SetDefaults Default values for a RouterObservabilityConfig.
func (r *RouterObservabilityConfig) SetDefaults() {
r.TraceVerbosity = types.MinimalVerbosity
} }
// +k8s:deepcopy-gen=true // +k8s:deepcopy-gen=true

View File

@ -1335,13 +1335,13 @@ func (in *RouterObservabilityConfig) DeepCopyInto(out *RouterObservabilityConfig
*out = new(bool) *out = new(bool)
**out = **in **out = **in
} }
if in.Tracing != nil { if in.Metrics != nil {
in, out := &in.Tracing, &out.Tracing in, out := &in.Metrics, &out.Metrics
*out = new(bool) *out = new(bool)
**out = **in **out = **in
} }
if in.Metrics != nil { if in.Tracing != nil {
in, out := &in.Metrics, &out.Metrics in, out := &in.Tracing, &out.Tracing
*out = new(bool) *out = new(bool)
**out = **in **out = **in
} }

View File

@ -26,9 +26,10 @@ const (
type Configuration struct { type Configuration struct {
Routers map[string]*RouterInfo `json:"routers,omitempty"` Routers map[string]*RouterInfo `json:"routers,omitempty"`
Middlewares map[string]*MiddlewareInfo `json:"middlewares,omitempty"` Middlewares map[string]*MiddlewareInfo `json:"middlewares,omitempty"`
TCPMiddlewares map[string]*TCPMiddlewareInfo `json:"tcpMiddlewares,omitempty"`
Services map[string]*ServiceInfo `json:"services,omitempty"` Services map[string]*ServiceInfo `json:"services,omitempty"`
Models map[string]*dynamic.Model `json:"-"`
TCPRouters map[string]*TCPRouterInfo `json:"tcpRouters,omitempty"` TCPRouters map[string]*TCPRouterInfo `json:"tcpRouters,omitempty"`
TCPMiddlewares map[string]*TCPMiddlewareInfo `json:"tcpMiddlewares,omitempty"`
TCPServices map[string]*TCPServiceInfo `json:"tcpServices,omitempty"` TCPServices map[string]*TCPServiceInfo `json:"tcpServices,omitempty"`
UDPRouters map[string]*UDPRouterInfo `json:"udpRouters,omitempty"` UDPRouters map[string]*UDPRouterInfo `json:"udpRouters,omitempty"`
UDPServices map[string]*UDPServiceInfo `json:"udpServices,omitempty"` UDPServices map[string]*UDPServiceInfo `json:"udpServices,omitempty"`
@ -66,6 +67,8 @@ func NewConfig(conf dynamic.Configuration) *Configuration {
runtimeConfig.Middlewares[k] = &MiddlewareInfo{Middleware: v, Status: StatusEnabled} runtimeConfig.Middlewares[k] = &MiddlewareInfo{Middleware: v, Status: StatusEnabled}
} }
} }
runtimeConfig.Models = conf.HTTP.Models
} }
if conf.TCP != nil { if conf.TCP != nil {

View File

@ -165,15 +165,17 @@ func (u *UDPConfig) SetDefaults() {
// ObservabilityConfig holds the observability configuration for an entry point. // ObservabilityConfig holds the observability configuration for an entry point.
type ObservabilityConfig struct { type ObservabilityConfig struct {
AccessLogs *bool `json:"accessLogs,omitempty" toml:"accessLogs,omitempty" yaml:"accessLogs,omitempty" export:"true"` AccessLogs *bool `description:"Enables access-logs for this entryPoint." json:"accessLogs,omitempty" toml:"accessLogs,omitempty" yaml:"accessLogs,omitempty" export:"true"`
Tracing *bool `json:"tracing,omitempty" toml:"tracing,omitempty" yaml:"tracing,omitempty" export:"true"` Metrics *bool `description:"Enables metrics for this entryPoint." json:"metrics,omitempty" toml:"metrics,omitempty" yaml:"metrics,omitempty" export:"true"`
Metrics *bool `json:"metrics,omitempty" toml:"metrics,omitempty" yaml:"metrics,omitempty" export:"true"` Tracing *bool `description:"Enables tracing for this entryPoint." json:"tracing,omitempty" toml:"tracing,omitempty" yaml:"tracing,omitempty" export:"true"`
TraceVerbosity types.TracingVerbosity `description:"Defines the tracing verbosity level for this entryPoint." json:"traceVerbosity,omitempty" toml:"traceVerbosity,omitempty" yaml:"traceVerbosity,omitempty" export:"true"`
} }
// SetDefaults sets the default values. // SetDefaults sets the default values.
func (o *ObservabilityConfig) SetDefaults() { func (o *ObservabilityConfig) SetDefaults() {
defaultValue := true defaultValue := true
o.AccessLogs = &defaultValue o.AccessLogs = &defaultValue
o.Tracing = &defaultValue
o.Metrics = &defaultValue o.Metrics = &defaultValue
o.Tracing = &defaultValue
o.TraceVerbosity = types.MinimalVerbosity
} }

View File

@ -205,7 +205,7 @@ func (a *LifeCycle) SetDefaults() {
// Tracing holds the tracing configuration. // Tracing holds the tracing configuration.
type Tracing struct { type Tracing struct {
ServiceName string `description:"Sets the name for this service." json:"serviceName,omitempty" toml:"serviceName,omitempty" yaml:"serviceName,omitempty" export:"true"` ServiceName string `description:"Defines the service name resource attribute." json:"serviceName,omitempty" toml:"serviceName,omitempty" yaml:"serviceName,omitempty" export:"true"`
ResourceAttributes map[string]string `description:"Defines additional resource attributes (key:value)." json:"resourceAttributes,omitempty" toml:"resourceAttributes,omitempty" yaml:"resourceAttributes,omitempty" export:"true"` ResourceAttributes map[string]string `description:"Defines additional resource attributes (key:value)." json:"resourceAttributes,omitempty" toml:"resourceAttributes,omitempty" yaml:"resourceAttributes,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"`

View File

@ -1,6 +1,7 @@
package logs package logs
import ( import (
"context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"reflect" "reflect"
@ -12,12 +13,12 @@ import (
) )
// SetupOTelLogger sets up the OpenTelemetry logger. // SetupOTelLogger sets up the OpenTelemetry logger.
func SetupOTelLogger(logger zerolog.Logger, config *types.OTelLog) (zerolog.Logger, error) { func SetupOTelLogger(ctx context.Context, logger zerolog.Logger, config *types.OTelLog) (zerolog.Logger, error) {
if config == nil { if config == nil {
return logger, nil return logger, nil
} }
provider, err := config.NewLoggerProvider() provider, err := config.NewLoggerProvider(ctx)
if err != nil { if err != nil {
return zerolog.Logger{}, fmt.Errorf("setting up OpenTelemetry logger provider: %w", err) return zerolog.Logger{}, fmt.Errorf("setting up OpenTelemetry logger provider: %w", err)
} }

View File

@ -171,7 +171,7 @@ func TestLog(t *testing.T) {
out := zerolog.MultiLevelWriter(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339}) out := zerolog.MultiLevelWriter(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339})
logger := zerolog.New(out).With().Caller().Logger() logger := zerolog.New(out).With().Caller().Logger()
logger, err := SetupOTelLogger(logger, config) logger, err := SetupOTelLogger(t.Context(), logger, config)
require.NoError(t, err) require.NoError(t, err)
ctx := trace.ContextWithSpanContext(t.Context(), trace.NewSpanContext(trace.SpanContextConfig{ ctx := trace.ContextWithSpanContext(t.Context(), trace.NewSpanContext(trace.SpanContextConfig{

View File

@ -206,15 +206,27 @@ func newOpenTelemetryMeterProvider(ctx context.Context, config *types.OTLP) (*sd
return nil, fmt.Errorf("creating exporter: %w", err) return nil, fmt.Errorf("creating exporter: %w", err)
} }
var resAttrs []attribute.KeyValue
for k, v := range config.ResourceAttributes {
resAttrs = append(resAttrs, attribute.String(k, v))
}
res, err := resource.New(ctx, res, err := resource.New(ctx,
resource.WithAttributes(semconv.ServiceNameKey.String(config.ServiceName)),
resource.WithAttributes(semconv.ServiceVersionKey.String(version.Version)),
resource.WithContainer(), resource.WithContainer(),
resource.WithFromEnv(),
resource.WithHost(), resource.WithHost(),
resource.WithOS(), resource.WithOS(),
resource.WithProcess(), resource.WithProcess(),
resource.WithTelemetrySDK(), resource.WithTelemetrySDK(),
resource.WithDetectors(types.K8sAttributesDetector{}),
// The following order allows the user to override the service name and version,
// as well as any other attributes set by the above detectors.
resource.WithAttributes(
semconv.ServiceName(config.ServiceName),
semconv.ServiceVersion(version.Version),
),
resource.WithAttributes(resAttrs...),
// Use the environment variables to allow overriding above resource attributes.
resource.WithFromEnv(),
) )
if err != nil { if err != nil {
return nil, fmt.Errorf("building resource: %w", err) return nil, fmt.Errorf("building resource: %w", err)

View File

@ -21,6 +21,7 @@ import (
ptypes "github.com/traefik/paerser/types" ptypes "github.com/traefik/paerser/types"
"github.com/traefik/traefik/v3/pkg/logs" "github.com/traefik/traefik/v3/pkg/logs"
"github.com/traefik/traefik/v3/pkg/middlewares/capture" "github.com/traefik/traefik/v3/pkg/middlewares/capture"
"github.com/traefik/traefik/v3/pkg/middlewares/observability"
traefiktls "github.com/traefik/traefik/v3/pkg/tls" traefiktls "github.com/traefik/traefik/v3/pkg/tls"
"github.com/traefik/traefik/v3/pkg/types" "github.com/traefik/traefik/v3/pkg/types"
"go.opentelemetry.io/contrib/bridges/otellogrus" "go.opentelemetry.io/contrib/bridges/otellogrus"
@ -69,17 +70,22 @@ type Handler struct {
wg sync.WaitGroup wg sync.WaitGroup
} }
// WrapHandler Wraps access log handler into an Alice Constructor. // AliceConstructor returns an alice.Constructor that wraps the Handler (conditionally) in a middleware chain.
func WrapHandler(handler *Handler) alice.Constructor { func (h *Handler) AliceConstructor() alice.Constructor {
return func(next http.Handler) (http.Handler, error) { return func(next http.Handler) (http.Handler, error) {
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
handler.ServeHTTP(rw, req, next) if h == nil {
next.ServeHTTP(rw, req)
return
}
h.ServeHTTP(rw, req, next)
}), nil }), nil
} }
} }
// NewHandler creates a new Handler. // NewHandler creates a new Handler.
func NewHandler(config *types.AccessLog) (*Handler, error) { func NewHandler(ctx context.Context, config *types.AccessLog) (*Handler, error) {
var file io.WriteCloser = noopCloser{os.Stdout} var file io.WriteCloser = noopCloser{os.Stdout}
if len(config.FilePath) > 0 { if len(config.FilePath) > 0 {
f, err := openAccessLogFile(config.FilePath) f, err := openAccessLogFile(config.FilePath)
@ -110,7 +116,7 @@ func NewHandler(config *types.AccessLog) (*Handler, error) {
} }
if config.OTLP != nil { if config.OTLP != nil {
otelLoggerProvider, err := config.OTLP.NewLoggerProvider() otelLoggerProvider, err := config.OTLP.NewLoggerProvider(ctx)
if err != nil { if err != nil {
return nil, fmt.Errorf("setting up OpenTelemetry logger provider: %w", err) return nil, fmt.Errorf("setting up OpenTelemetry logger provider: %w", err)
} }
@ -196,6 +202,12 @@ func GetLogData(req *http.Request) *LogData {
} }
func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request, next http.Handler) { func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request, next http.Handler) {
if !observability.AccessLogsEnabled(req.Context()) {
next.ServeHTTP(rw, req)
return
}
now := time.Now().UTC() now := time.Now().UTC()
core := CoreLogData{ core := CoreLogData{

View File

@ -7,6 +7,7 @@ import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
func TestCommonLogFormatter_Format(t *testing.T) { func TestCommonLogFormatter_Format(t *testing.T) {
@ -82,8 +83,9 @@ func TestCommonLogFormatter_Format(t *testing.T) {
}, },
} }
// Set timezone to Etc/GMT+9 to have a constant behavior var err error
t.Setenv("TZ", "Etc/GMT+9") time.Local, err = time.LoadLocation("Etc/GMT+9")
require.NoError(t, err)
for _, test := range testCases { for _, test := range testCases {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {

View File

@ -25,6 +25,7 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
ptypes "github.com/traefik/paerser/types" ptypes "github.com/traefik/paerser/types"
"github.com/traefik/traefik/v3/pkg/middlewares/capture" "github.com/traefik/traefik/v3/pkg/middlewares/capture"
"github.com/traefik/traefik/v3/pkg/middlewares/observability"
"github.com/traefik/traefik/v3/pkg/types" "github.com/traefik/traefik/v3/pkg/types"
"go.opentelemetry.io/collector/pdata/plog/plogotlp" "go.opentelemetry.io/collector/pdata/plog/plogotlp"
"go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/attribute"
@ -84,7 +85,7 @@ func TestOTelAccessLog(t *testing.T) {
}, },
}, },
} }
logHandler, err := NewHandler(config) logHandler, err := NewHandler(t.Context(), config)
require.NoError(t, err) require.NoError(t, err)
t.Cleanup(func() { t.Cleanup(func() {
err := logHandler.Close() err := logHandler.Close()
@ -105,7 +106,15 @@ func TestOTelAccessLog(t *testing.T) {
chain := alice.New() chain := alice.New()
chain = chain.Append(capture.Wrap) chain = chain.Append(capture.Wrap)
chain = chain.Append(WrapHandler(logHandler))
// Injection of the observability variables in the request context.
chain = chain.Append(func(next http.Handler) (http.Handler, error) {
return observability.WithObservabilityHandler(next, observability.Observability{
AccessLogsEnabled: true,
}), nil
})
chain = chain.Append(logHandler.AliceConstructor())
handler, err := chain.Then(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { handler, err := chain.Then(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.WriteHeader(http.StatusOK) rw.WriteHeader(http.StatusOK)
})) }))
@ -129,7 +138,7 @@ func TestLogRotation(t *testing.T) {
rotatedFileName := fileName + ".rotated" rotatedFileName := fileName + ".rotated"
config := &types.AccessLog{FilePath: fileName, Format: CommonFormat} config := &types.AccessLog{FilePath: fileName, Format: CommonFormat}
logHandler, err := NewHandler(config) logHandler, err := NewHandler(t.Context(), config)
require.NoError(t, err) require.NoError(t, err)
t.Cleanup(func() { t.Cleanup(func() {
err := logHandler.Close() err := logHandler.Close()
@ -138,7 +147,15 @@ func TestLogRotation(t *testing.T) {
chain := alice.New() chain := alice.New()
chain = chain.Append(capture.Wrap) chain = chain.Append(capture.Wrap)
chain = chain.Append(WrapHandler(logHandler))
// Injection of the observability variables in the request context.
chain = chain.Append(func(next http.Handler) (http.Handler, error) {
return observability.WithObservabilityHandler(next, observability.Observability{
AccessLogsEnabled: true,
}), nil
})
chain = chain.Append(logHandler.AliceConstructor())
handler, err := chain.Then(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { handler, err := chain.Then(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.WriteHeader(http.StatusOK) rw.WriteHeader(http.StatusOK)
})) }))
@ -265,7 +282,7 @@ func TestLoggerHeaderFields(t *testing.T) {
Fields: &test.accessLogFields, Fields: &test.accessLogFields,
} }
logger, err := NewHandler(config) logger, err := NewHandler(t.Context(), config)
require.NoError(t, err) require.NoError(t, err)
t.Cleanup(func() { t.Cleanup(func() {
err := logger.Close() err := logger.Close()
@ -290,7 +307,15 @@ func TestLoggerHeaderFields(t *testing.T) {
chain := alice.New() chain := alice.New()
chain = chain.Append(capture.Wrap) chain = chain.Append(capture.Wrap)
chain = chain.Append(WrapHandler(logger))
// Injection of the observability variables in the request context.
chain = chain.Append(func(next http.Handler) (http.Handler, error) {
return observability.WithObservabilityHandler(next, observability.Observability{
AccessLogsEnabled: true,
}), nil
})
chain = chain.Append(logger.AliceConstructor())
handler, err := chain.Then(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { handler, err := chain.Then(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.WriteHeader(http.StatusOK) rw.WriteHeader(http.StatusOK)
})) }))
@ -954,7 +979,7 @@ func captureStdout(t *testing.T) (out *os.File, restoreStdout func()) {
func doLoggingTLSOpt(t *testing.T, config *types.AccessLog, enableTLS, tracing bool) { func doLoggingTLSOpt(t *testing.T, config *types.AccessLog, enableTLS, tracing bool) {
t.Helper() t.Helper()
logger, err := NewHandler(config) logger, err := NewHandler(t.Context(), config)
require.NoError(t, err) require.NoError(t, err)
t.Cleanup(func() { t.Cleanup(func() {
err := logger.Close() err := logger.Close()
@ -998,7 +1023,15 @@ func doLoggingTLSOpt(t *testing.T, config *types.AccessLog, enableTLS, tracing b
chain := alice.New() chain := alice.New()
chain = chain.Append(capture.Wrap) chain = chain.Append(capture.Wrap)
chain = chain.Append(WrapHandler(logger))
// Injection of the observability variables in the request context.
chain = chain.Append(func(next http.Handler) (http.Handler, error) {
return observability.WithObservabilityHandler(next, observability.Observability{
AccessLogsEnabled: true,
}), nil
})
chain = chain.Append(logger.AliceConstructor())
handler, err := chain.Then(http.HandlerFunc(logWriterTestHandlerFunc)) handler, err := chain.Then(http.HandlerFunc(logWriterTestHandlerFunc))
require.NoError(t, err) require.NoError(t, err)
@ -1043,7 +1076,7 @@ func logWriterTestHandlerFunc(rw http.ResponseWriter, r *http.Request) {
func doLoggingWithAbortedStream(t *testing.T, config *types.AccessLog) { func doLoggingWithAbortedStream(t *testing.T, config *types.AccessLog) {
t.Helper() t.Helper()
logger, err := NewHandler(config) logger, err := NewHandler(t.Context(), config)
require.NoError(t, err) require.NoError(t, err)
t.Cleanup(func() { t.Cleanup(func() {
err := logger.Close() err := logger.Close()
@ -1085,7 +1118,15 @@ func doLoggingWithAbortedStream(t *testing.T, config *types.AccessLog) {
}), nil }), nil
}) })
chain = chain.Append(capture.Wrap) chain = chain.Append(capture.Wrap)
chain = chain.Append(WrapHandler(logger))
// Injection of the observability variables in the request context.
chain = chain.Append(func(next http.Handler) (http.Handler, error) {
return observability.WithObservabilityHandler(next, observability.Observability{
AccessLogsEnabled: true,
}), nil
})
chain = chain.Append(logger.AliceConstructor())
service := NewFieldHandler(http.HandlerFunc(streamBackend), ServiceURL, "http://stream", nil) service := NewFieldHandler(http.HandlerFunc(streamBackend), ServiceURL, "http://stream", nil)
service = NewFieldHandler(service, ServiceAddr, "127.0.0.1", nil) service = NewFieldHandler(service, ServiceAddr, "127.0.0.1", nil)

View File

@ -7,7 +7,6 @@ import (
"github.com/traefik/traefik/v3/pkg/config/dynamic" "github.com/traefik/traefik/v3/pkg/config/dynamic"
"github.com/traefik/traefik/v3/pkg/middlewares" "github.com/traefik/traefik/v3/pkg/middlewares"
"go.opentelemetry.io/otel/trace"
) )
const ( const (
@ -39,8 +38,8 @@ func New(ctx context.Context, next http.Handler, config dynamic.AddPrefix, name
return result, nil return result, nil
} }
func (a *addPrefix) GetTracingInformation() (string, string, trace.SpanKind) { func (a *addPrefix) GetTracingInformation() (string, string) {
return a.name, typeName, trace.SpanKindInternal return a.name, typeName
} }
func (a *addPrefix) ServeHTTP(rw http.ResponseWriter, req *http.Request) { func (a *addPrefix) ServeHTTP(rw http.ResponseWriter, req *http.Request) {

View File

@ -12,7 +12,6 @@ import (
"github.com/traefik/traefik/v3/pkg/middlewares" "github.com/traefik/traefik/v3/pkg/middlewares"
"github.com/traefik/traefik/v3/pkg/middlewares/accesslog" "github.com/traefik/traefik/v3/pkg/middlewares/accesslog"
"github.com/traefik/traefik/v3/pkg/middlewares/observability" "github.com/traefik/traefik/v3/pkg/middlewares/observability"
"go.opentelemetry.io/otel/trace"
"golang.org/x/sync/singleflight" "golang.org/x/sync/singleflight"
) )
@ -61,8 +60,8 @@ func NewBasic(ctx context.Context, next http.Handler, authConfig dynamic.BasicAu
return ba, nil return ba, nil
} }
func (b *basicAuth) GetTracingInformation() (string, string, trace.SpanKind) { func (b *basicAuth) GetTracingInformation() (string, string) {
return b.name, typeNameBasic, trace.SpanKindInternal return b.name, typeNameBasic
} }
func (b *basicAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) { func (b *basicAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {

View File

@ -12,7 +12,6 @@ import (
"github.com/traefik/traefik/v3/pkg/middlewares" "github.com/traefik/traefik/v3/pkg/middlewares"
"github.com/traefik/traefik/v3/pkg/middlewares/accesslog" "github.com/traefik/traefik/v3/pkg/middlewares/accesslog"
"github.com/traefik/traefik/v3/pkg/middlewares/observability" "github.com/traefik/traefik/v3/pkg/middlewares/observability"
"go.opentelemetry.io/otel/trace"
) )
const ( const (
@ -54,8 +53,8 @@ func NewDigest(ctx context.Context, next http.Handler, authConfig dynamic.Digest
return da, nil return da, nil
} }
func (d *digestAuth) GetTracingInformation() (string, string, trace.SpanKind) { func (d *digestAuth) GetTracingInformation() (string, string) {
return d.name, typeNameDigest, trace.SpanKindInternal return d.name, typeNameDigest
} }
func (d *digestAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) { func (d *digestAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {

View File

@ -131,8 +131,8 @@ func NewForward(ctx context.Context, next http.Handler, config dynamic.ForwardAu
return fa, nil return fa, nil
} }
func (fa *forwardAuth) GetTracingInformation() (string, string, trace.SpanKind) { func (fa *forwardAuth) GetTracingInformation() (string, string) {
return fa.name, typeNameForward, trace.SpanKindInternal return fa.name, typeNameForward
} }
func (fa *forwardAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) { func (fa *forwardAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
@ -180,7 +180,7 @@ func (fa *forwardAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
var forwardSpan trace.Span var forwardSpan trace.Span
var tracer *tracing.Tracer var tracer *tracing.Tracer
if tracer = tracing.TracerFromContext(req.Context()); tracer != nil { if tracer = tracing.TracerFromContext(req.Context()); tracer != nil && observability.TracingEnabled(req.Context()) {
var tracingCtx context.Context var tracingCtx context.Context
tracingCtx, forwardSpan = tracer.Start(req.Context(), "AuthRequest", trace.WithSpanKind(trace.SpanKindClient)) tracingCtx, forwardSpan = tracer.Start(req.Context(), "AuthRequest", trace.WithSpanKind(trace.SpanKindClient))
defer forwardSpan.End() defer forwardSpan.End()

View File

@ -16,6 +16,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/traefik/traefik/v3/pkg/config/dynamic" "github.com/traefik/traefik/v3/pkg/config/dynamic"
"github.com/traefik/traefik/v3/pkg/middlewares/observability"
"github.com/traefik/traefik/v3/pkg/proxy/httputil" "github.com/traefik/traefik/v3/pkg/proxy/httputil"
"github.com/traefik/traefik/v3/pkg/testhelpers" "github.com/traefik/traefik/v3/pkg/testhelpers"
"github.com/traefik/traefik/v3/pkg/tracing" "github.com/traefik/traefik/v3/pkg/tracing"
@ -756,6 +757,10 @@ func TestForwardAuthTracing(t *testing.T) {
next, err := NewForward(t.Context(), next, auth, "authTest") next, err := NewForward(t.Context(), next, auth, "authTest")
require.NoError(t, err) require.NoError(t, err)
next = observability.WithObservabilityHandler(next, observability.Observability{
TracingEnabled: true,
})
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", nil)
req.RemoteAddr = "10.0.0.1:1234" req.RemoteAddr = "10.0.0.1:1234"
req.Header.Set("User-Agent", "forward-test") req.Header.Set("User-Agent", "forward-test")

View File

@ -9,7 +9,6 @@ import (
"github.com/traefik/traefik/v3/pkg/logs" "github.com/traefik/traefik/v3/pkg/logs"
"github.com/traefik/traefik/v3/pkg/middlewares" "github.com/traefik/traefik/v3/pkg/middlewares"
oxybuffer "github.com/vulcand/oxy/v2/buffer" oxybuffer "github.com/vulcand/oxy/v2/buffer"
"go.opentelemetry.io/otel/trace"
) )
const ( const (
@ -48,8 +47,8 @@ func New(ctx context.Context, next http.Handler, config dynamic.Buffering, name
}, nil }, nil
} }
func (b *buffer) GetTracingInformation() (string, string, trace.SpanKind) { func (b *buffer) GetTracingInformation() (string, string) {
return b.name, typeName, trace.SpanKindInternal return b.name, typeName
} }
func (b *buffer) ServeHTTP(rw http.ResponseWriter, req *http.Request) { func (b *buffer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {

View File

@ -12,7 +12,6 @@ import (
"github.com/traefik/traefik/v3/pkg/middlewares" "github.com/traefik/traefik/v3/pkg/middlewares"
"github.com/traefik/traefik/v3/pkg/middlewares/observability" "github.com/traefik/traefik/v3/pkg/middlewares/observability"
"github.com/vulcand/oxy/v2/cbreaker" "github.com/vulcand/oxy/v2/cbreaker"
"go.opentelemetry.io/otel/trace"
) )
const typeName = "CircuitBreaker" const typeName = "CircuitBreaker"
@ -68,8 +67,8 @@ func New(ctx context.Context, next http.Handler, confCircuitBreaker dynamic.Circ
}, nil }, nil
} }
func (c *circuitBreaker) GetTracingInformation() (string, string, trace.SpanKind) { func (c *circuitBreaker) GetTracingInformation() (string, string) {
return c.name, typeName, trace.SpanKindInternal return c.name, typeName
} }
func (c *circuitBreaker) ServeHTTP(rw http.ResponseWriter, req *http.Request) { func (c *circuitBreaker) ServeHTTP(rw http.ResponseWriter, req *http.Request) {

View File

@ -13,7 +13,6 @@ import (
"github.com/klauspost/compress/zstd" "github.com/klauspost/compress/zstd"
"github.com/traefik/traefik/v3/pkg/config/dynamic" "github.com/traefik/traefik/v3/pkg/config/dynamic"
"github.com/traefik/traefik/v3/pkg/middlewares" "github.com/traefik/traefik/v3/pkg/middlewares"
"go.opentelemetry.io/otel/trace"
) )
const typeName = "Compress" const typeName = "Compress"
@ -181,8 +180,8 @@ func (c *compress) chooseHandler(typ string, rw http.ResponseWriter, req *http.R
} }
} }
func (c *compress) GetTracingInformation() (string, string, trace.SpanKind) { func (c *compress) GetTracingInformation() (string, string) {
return c.name, typeName, trace.SpanKindInternal return c.name, typeName
} }
func (c *compress) newGzipHandler() (http.Handler, error) { func (c *compress) newGzipHandler() (http.Handler, error) {

View File

@ -15,7 +15,6 @@ import (
"github.com/traefik/traefik/v3/pkg/middlewares/observability" "github.com/traefik/traefik/v3/pkg/middlewares/observability"
"github.com/traefik/traefik/v3/pkg/types" "github.com/traefik/traefik/v3/pkg/types"
"github.com/vulcand/oxy/v2/utils" "github.com/vulcand/oxy/v2/utils"
"go.opentelemetry.io/otel/trace"
) )
// Compile time validation that the response recorder implements http interfaces correctly. // Compile time validation that the response recorder implements http interfaces correctly.
@ -83,8 +82,8 @@ func New(ctx context.Context, next http.Handler, config dynamic.ErrorPage, servi
}, nil }, nil
} }
func (c *customErrors) GetTracingInformation() (string, string, trace.SpanKind) { func (c *customErrors) GetTracingInformation() (string, string) {
return c.name, typeName, trace.SpanKindInternal return c.name, typeName
} }
func (c *customErrors) ServeHTTP(rw http.ResponseWriter, req *http.Request) { func (c *customErrors) ServeHTTP(rw http.ResponseWriter, req *http.Request) {

View File

@ -6,7 +6,6 @@ import (
"github.com/traefik/traefik/v3/pkg/config/dynamic" "github.com/traefik/traefik/v3/pkg/config/dynamic"
"github.com/traefik/traefik/v3/pkg/middlewares" "github.com/traefik/traefik/v3/pkg/middlewares"
"go.opentelemetry.io/otel/trace"
) )
const requestHeaderModifierTypeName = "RequestHeaderModifier" const requestHeaderModifierTypeName = "RequestHeaderModifier"
@ -35,8 +34,8 @@ func NewRequestHeaderModifier(ctx context.Context, next http.Handler, config dyn
} }
} }
func (r *requestHeaderModifier) GetTracingInformation() (string, string, trace.SpanKind) { func (r *requestHeaderModifier) GetTracingInformation() (string, string) {
return r.name, requestHeaderModifierTypeName, trace.SpanKindUnspecified return r.name, requestHeaderModifierTypeName
} }
func (r *requestHeaderModifier) ServeHTTP(rw http.ResponseWriter, req *http.Request) { func (r *requestHeaderModifier) ServeHTTP(rw http.ResponseWriter, req *http.Request) {

View File

@ -6,7 +6,6 @@ import (
"github.com/traefik/traefik/v3/pkg/config/dynamic" "github.com/traefik/traefik/v3/pkg/config/dynamic"
"github.com/traefik/traefik/v3/pkg/middlewares" "github.com/traefik/traefik/v3/pkg/middlewares"
"go.opentelemetry.io/otel/trace"
) )
const responseHeaderModifierTypeName = "ResponseHeaderModifier" const responseHeaderModifierTypeName = "ResponseHeaderModifier"
@ -35,8 +34,8 @@ func NewResponseHeaderModifier(ctx context.Context, next http.Handler, config dy
} }
} }
func (r *responseHeaderModifier) GetTracingInformation() (string, string, trace.SpanKind) { func (r *responseHeaderModifier) GetTracingInformation() (string, string) {
return r.name, responseHeaderModifierTypeName, trace.SpanKindUnspecified return r.name, responseHeaderModifierTypeName
} }
func (r *responseHeaderModifier) ServeHTTP(rw http.ResponseWriter, req *http.Request) { func (r *responseHeaderModifier) ServeHTTP(rw http.ResponseWriter, req *http.Request) {

View File

@ -10,7 +10,6 @@ import (
"github.com/traefik/traefik/v3/pkg/config/dynamic" "github.com/traefik/traefik/v3/pkg/config/dynamic"
"github.com/traefik/traefik/v3/pkg/middlewares" "github.com/traefik/traefik/v3/pkg/middlewares"
"go.opentelemetry.io/otel/trace"
) )
const typeName = "RequestRedirect" const typeName = "RequestRedirect"
@ -52,8 +51,8 @@ func NewRequestRedirect(ctx context.Context, next http.Handler, conf dynamic.Req
}, nil }, nil
} }
func (r redirect) GetTracingInformation() (string, string, trace.SpanKind) { func (r redirect) GetTracingInformation() (string, string) {
return r.name, typeName, trace.SpanKindInternal return r.name, typeName
} }
func (r redirect) ServeHTTP(rw http.ResponseWriter, req *http.Request) { func (r redirect) ServeHTTP(rw http.ResponseWriter, req *http.Request) {

View File

@ -8,7 +8,6 @@ import (
"github.com/traefik/traefik/v3/pkg/config/dynamic" "github.com/traefik/traefik/v3/pkg/config/dynamic"
"github.com/traefik/traefik/v3/pkg/middlewares" "github.com/traefik/traefik/v3/pkg/middlewares"
"go.opentelemetry.io/otel/trace"
) )
const ( const (
@ -38,8 +37,8 @@ func NewURLRewrite(ctx context.Context, next http.Handler, conf dynamic.URLRewri
} }
} }
func (u urlRewrite) GetTracingInformation() (string, string, trace.SpanKind) { func (u urlRewrite) GetTracingInformation() (string, string) {
return u.name, typeName, trace.SpanKindInternal return u.name, typeName
} }
func (u urlRewrite) ServeHTTP(rw http.ResponseWriter, req *http.Request) { func (u urlRewrite) ServeHTTP(rw http.ResponseWriter, req *http.Request) {

View File

@ -8,7 +8,6 @@ import (
"github.com/traefik/traefik/v3/pkg/config/dynamic" "github.com/traefik/traefik/v3/pkg/config/dynamic"
"github.com/traefik/traefik/v3/pkg/middlewares" "github.com/traefik/traefik/v3/pkg/middlewares"
"go.opentelemetry.io/otel/trace"
) )
const ( const (
@ -58,8 +57,8 @@ func New(ctx context.Context, next http.Handler, cfg dynamic.Headers, name strin
}, nil }, nil
} }
func (h *headers) GetTracingInformation() (string, string, trace.SpanKind) { func (h *headers) GetTracingInformation() (string, string) {
return h.name, typeName, trace.SpanKindInternal return h.name, typeName
} }
func (h *headers) ServeHTTP(rw http.ResponseWriter, req *http.Request) { func (h *headers) ServeHTTP(rw http.ResponseWriter, req *http.Request) {

View File

@ -13,7 +13,6 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/traefik/traefik/v3/pkg/config/dynamic" "github.com/traefik/traefik/v3/pkg/config/dynamic"
"go.opentelemetry.io/otel/trace"
) )
func TestNew_withoutOptions(t *testing.T) { func TestNew_withoutOptions(t *testing.T) {
@ -107,11 +106,10 @@ func Test_headers_getTracingInformation(t *testing.T) {
name: "testing", name: "testing",
} }
name, typeName, spanKind := mid.GetTracingInformation() name, typeName := mid.GetTracingInformation()
assert.Equal(t, "testing", name) assert.Equal(t, "testing", name)
assert.Equal(t, "Headers", typeName) assert.Equal(t, "Headers", typeName)
assert.Equal(t, trace.SpanKindInternal, spanKind)
} }
// This test is an adapted version of net/http/httputil.Test1xxResponses test. // This test is an adapted version of net/http/httputil.Test1xxResponses test.

View File

@ -10,7 +10,6 @@ import (
"github.com/traefik/traefik/v3/pkg/logs" "github.com/traefik/traefik/v3/pkg/logs"
"github.com/traefik/traefik/v3/pkg/middlewares" "github.com/traefik/traefik/v3/pkg/middlewares"
"github.com/vulcand/oxy/v2/connlimit" "github.com/vulcand/oxy/v2/connlimit"
"go.opentelemetry.io/otel/trace"
) )
const ( const (
@ -53,8 +52,8 @@ func New(ctx context.Context, next http.Handler, config dynamic.InFlightReq, nam
return &inFlightReq{handler: handler, name: name}, nil return &inFlightReq{handler: handler, name: name}, nil
} }
func (i *inFlightReq) GetTracingInformation() (string, string, trace.SpanKind) { func (i *inFlightReq) GetTracingInformation() (string, string) {
return i.name, typeName, trace.SpanKindInternal return i.name, typeName
} }
func (i *inFlightReq) ServeHTTP(rw http.ResponseWriter, req *http.Request) { func (i *inFlightReq) ServeHTTP(rw http.ResponseWriter, req *http.Request) {

View File

@ -11,7 +11,6 @@ import (
"github.com/traefik/traefik/v3/pkg/ip" "github.com/traefik/traefik/v3/pkg/ip"
"github.com/traefik/traefik/v3/pkg/middlewares" "github.com/traefik/traefik/v3/pkg/middlewares"
"github.com/traefik/traefik/v3/pkg/middlewares/observability" "github.com/traefik/traefik/v3/pkg/middlewares/observability"
"go.opentelemetry.io/otel/trace"
) )
const ( const (
@ -65,8 +64,8 @@ func New(ctx context.Context, next http.Handler, config dynamic.IPAllowList, nam
}, nil }, nil
} }
func (al *ipAllowLister) GetTracingInformation() (string, string, trace.SpanKind) { func (al *ipAllowLister) GetTracingInformation() (string, string) {
return al.name, typeName, trace.SpanKindInternal return al.name, typeName
} }
func (al *ipAllowLister) ServeHTTP(rw http.ResponseWriter, req *http.Request) { func (al *ipAllowLister) ServeHTTP(rw http.ResponseWriter, req *http.Request) {

View File

@ -11,7 +11,6 @@ import (
"github.com/traefik/traefik/v3/pkg/ip" "github.com/traefik/traefik/v3/pkg/ip"
"github.com/traefik/traefik/v3/pkg/middlewares" "github.com/traefik/traefik/v3/pkg/middlewares"
"github.com/traefik/traefik/v3/pkg/middlewares/observability" "github.com/traefik/traefik/v3/pkg/middlewares/observability"
"go.opentelemetry.io/otel/trace"
) )
const ( const (
@ -55,8 +54,8 @@ func New(ctx context.Context, next http.Handler, config dynamic.IPWhiteList, nam
}, nil }, nil
} }
func (wl *ipWhiteLister) GetTracingInformation() (string, string, trace.SpanKind) { func (wl *ipWhiteLister) GetTracingInformation() (string, string) {
return wl.name, typeName, trace.SpanKindInternal return wl.name, typeName
} }
func (wl *ipWhiteLister) ServeHTTP(rw http.ResponseWriter, req *http.Request) { func (wl *ipWhiteLister) ServeHTTP(rw http.ResponseWriter, req *http.Request) {

View File

@ -18,7 +18,6 @@ import (
"github.com/traefik/traefik/v3/pkg/middlewares/observability" "github.com/traefik/traefik/v3/pkg/middlewares/observability"
"github.com/traefik/traefik/v3/pkg/middlewares/retry" "github.com/traefik/traefik/v3/pkg/middlewares/retry"
traefiktls "github.com/traefik/traefik/v3/pkg/tls" traefiktls "github.com/traefik/traefik/v3/pkg/tls"
"go.opentelemetry.io/otel/trace"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
) )
@ -93,33 +92,45 @@ func NewServiceMiddleware(ctx context.Context, next http.Handler, registry metri
} }
} }
// WrapEntryPointHandler Wraps metrics entrypoint to alice.Constructor. // EntryPointMetricsHandler returns the metrics entrypoint handler.
func WrapEntryPointHandler(ctx context.Context, registry metrics.Registry, entryPointName string) alice.Constructor { func EntryPointMetricsHandler(ctx context.Context, registry metrics.Registry, entryPointName string) alice.Constructor {
return func(next http.Handler) (http.Handler, error) { return func(next http.Handler) (http.Handler, error) {
if registry == nil || !registry.IsEpEnabled() {
return next, nil
}
return NewEntryPointMiddleware(ctx, next, registry, entryPointName), nil return NewEntryPointMiddleware(ctx, next, registry, entryPointName), nil
} }
} }
// WrapRouterHandler Wraps metrics router to alice.Constructor. // RouterMetricsHandler returns the metrics router handler.
func WrapRouterHandler(ctx context.Context, registry metrics.Registry, routerName string, serviceName string) alice.Constructor { func RouterMetricsHandler(ctx context.Context, registry metrics.Registry, routerName string, serviceName string) alice.Constructor {
return func(next http.Handler) (http.Handler, error) { return func(next http.Handler) (http.Handler, error) {
if registry == nil || !registry.IsRouterEnabled() {
return next, nil
}
return NewRouterMiddleware(ctx, next, registry, routerName, serviceName), nil return NewRouterMiddleware(ctx, next, registry, routerName, serviceName), nil
} }
} }
// WrapServiceHandler Wraps metrics service to alice.Constructor. // ServiceMetricsHandler returns the metrics service handler.
func WrapServiceHandler(ctx context.Context, registry metrics.Registry, serviceName string) alice.Constructor { func ServiceMetricsHandler(ctx context.Context, registry metrics.Registry, serviceName string) alice.Constructor {
return func(next http.Handler) (http.Handler, error) { return func(next http.Handler) (http.Handler, error) {
if registry == nil || !registry.IsSvcEnabled() {
return next, nil
}
return NewServiceMiddleware(ctx, next, registry, serviceName), nil return NewServiceMiddleware(ctx, next, registry, serviceName), nil
} }
} }
func (m *metricsMiddleware) GetTracingInformation() (string, string, trace.SpanKind) { func (m *metricsMiddleware) GetTracingInformation() (string, string) {
return m.name, typeName, trace.SpanKindInternal return m.name, typeName
} }
func (m *metricsMiddleware) ServeHTTP(rw http.ResponseWriter, req *http.Request) { func (m *metricsMiddleware) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
if val := req.Context().Value(observability.DisableMetricsKey); val != nil { if !observability.MetricsEnabled(req.Context()) {
m.next.ServeHTTP(rw, req) m.next.ServeHTTP(rw, req)
return return
} }

View File

@ -48,11 +48,17 @@ func newEntryPoint(ctx context.Context, tracer *tracing.Tracer, entryPointName s
} }
func (e *entryPointTracing) ServeHTTP(rw http.ResponseWriter, req *http.Request) { func (e *entryPointTracing) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
if e.tracer == nil || !TracingEnabled(req.Context()) {
e.next.ServeHTTP(rw, req)
return
}
tracingCtx := tracing.ExtractCarrierIntoContext(req.Context(), req.Header) tracingCtx := tracing.ExtractCarrierIntoContext(req.Context(), req.Header)
start := time.Now() start := time.Now()
tracingCtx, span := e.tracer.Start(tracingCtx, "EntryPoint", trace.WithSpanKind(trace.SpanKindServer), trace.WithTimestamp(start)) tracingCtx, span := e.tracer.Start(tracingCtx, "EntryPoint", trace.WithSpanKind(trace.SpanKindServer), trace.WithTimestamp(start))
// Associate the request context with the logger. // Associate the request context with the logger.
// This allows the logger to be aware of the tracing context and log accordingly (TraceID, SpanID, etc.).
logger := log.Ctx(tracingCtx).With().Ctx(tracingCtx).Logger() logger := log.Ctx(tracingCtx).With().Ctx(tracingCtx).Logger()
loggerCtx := logger.WithContext(tracingCtx) loggerCtx := logger.WithContext(tracingCtx)

View File

@ -14,7 +14,7 @@ import (
// Traceable embeds tracing information. // Traceable embeds tracing information.
type Traceable interface { type Traceable interface {
GetTracingInformation() (name string, typeName string, spanKind trace.SpanKind) GetTracingInformation() (name string, typeName string)
} }
// WrapMiddleware adds traceability to an alice.Constructor. // WrapMiddleware adds traceability to an alice.Constructor.
@ -29,21 +29,20 @@ func WrapMiddleware(ctx context.Context, constructor alice.Constructor) alice.Co
} }
if traceableHandler, ok := handler.(Traceable); ok { if traceableHandler, ok := handler.(Traceable); ok {
name, typeName, spanKind := traceableHandler.GetTracingInformation() name, typeName := traceableHandler.GetTracingInformation()
log.Ctx(ctx).Debug().Str(logs.MiddlewareName, name).Msg("Adding tracing to middleware") log.Ctx(ctx).Debug().Str(logs.MiddlewareName, name).Msg("Adding tracing to middleware")
return NewMiddleware(handler, name, typeName, spanKind), nil return NewMiddleware(handler, name, typeName), nil
} }
return handler, nil return handler, nil
} }
} }
// NewMiddleware returns a http.Handler struct. // NewMiddleware returns a http.Handler struct.
func NewMiddleware(next http.Handler, name string, typeName string, spanKind trace.SpanKind) http.Handler { func NewMiddleware(next http.Handler, name string, typeName string) http.Handler {
return &middlewareTracing{ return &middlewareTracing{
next: next, next: next,
name: name, name: name,
typeName: typeName, typeName: typeName,
spanKind: spanKind,
} }
} }
@ -52,12 +51,11 @@ type middlewareTracing struct {
next http.Handler next http.Handler
name string name string
typeName string typeName string
spanKind trace.SpanKind
} }
func (w *middlewareTracing) ServeHTTP(rw http.ResponseWriter, req *http.Request) { func (w *middlewareTracing) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
if tracer := tracing.TracerFromContext(req.Context()); tracer != nil { if tracer := tracing.TracerFromContext(req.Context()); tracer != nil && DetailedTracingEnabled(req.Context()) {
tracingCtx, span := tracer.Start(req.Context(), w.typeName, trace.WithSpanKind(w.spanKind)) tracingCtx, span := tracer.Start(req.Context(), w.typeName, trace.WithSpanKind(trace.SpanKindInternal))
defer span.End() defer span.End()
req = req.WithContext(tracingCtx) req = req.WithContext(tracingCtx)

View File

@ -3,6 +3,7 @@ package observability
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/trace"
@ -10,8 +11,58 @@ import (
type contextKey int type contextKey int
// DisableMetricsKey is a context key used to disable the metrics. const observabilityKey contextKey = iota
const DisableMetricsKey contextKey = iota
type Observability struct {
AccessLogsEnabled bool
MetricsEnabled bool
SemConvMetricsEnabled bool
TracingEnabled bool
DetailedTracingEnabled bool
}
// WithObservabilityHandler sets the observability state in the context for the next handler.
// This is also used for testing purposes to control whether access logs are enabled or not.
func WithObservabilityHandler(next http.Handler, obs Observability) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
next.ServeHTTP(rw, req.WithContext(WithObservability(req.Context(), obs)))
})
}
// WithObservability injects the observability state into the context.
func WithObservability(ctx context.Context, obs Observability) context.Context {
return context.WithValue(ctx, observabilityKey, obs)
}
// AccessLogsEnabled returns whether access-logs are enabled.
func AccessLogsEnabled(ctx context.Context) bool {
obs, ok := ctx.Value(observabilityKey).(Observability)
return ok && obs.AccessLogsEnabled
}
// MetricsEnabled returns whether metrics are enabled.
func MetricsEnabled(ctx context.Context) bool {
obs, ok := ctx.Value(observabilityKey).(Observability)
return ok && obs.MetricsEnabled
}
// SemConvMetricsEnabled returns whether metrics are enabled.
func SemConvMetricsEnabled(ctx context.Context) bool {
obs, ok := ctx.Value(observabilityKey).(Observability)
return ok && obs.SemConvMetricsEnabled
}
// TracingEnabled returns whether tracing is enabled.
func TracingEnabled(ctx context.Context) bool {
obs, ok := ctx.Value(observabilityKey).(Observability)
return ok && obs.TracingEnabled
}
// DetailedTracingEnabled returns whether detailed tracing is enabled.
func DetailedTracingEnabled(ctx context.Context) bool {
obs, ok := ctx.Value(observabilityKey).(Observability)
return ok && obs.DetailedTracingEnabled
}
// SetStatusErrorf flags the span as in error and log an event. // SetStatusErrorf flags the span as in error and log an event.
func SetStatusErrorf(ctx context.Context, format string, args ...interface{}) { func SetStatusErrorf(ctx context.Context, format string, args ...interface{}) {

View File

@ -45,7 +45,7 @@ func newRouter(ctx context.Context, router, routerRule, service string, next htt
} }
func (f *routerTracing) ServeHTTP(rw http.ResponseWriter, req *http.Request) { func (f *routerTracing) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
if tracer := tracing.TracerFromContext(req.Context()); tracer != nil { if tracer := tracing.TracerFromContext(req.Context()); tracer != nil && DetailedTracingEnabled(req.Context()) {
tracingCtx, span := tracer.Start(req.Context(), "Router", trace.WithSpanKind(trace.SpanKindInternal)) tracingCtx, span := tracer.Start(req.Context(), "Router", trace.WithSpanKind(trace.SpanKindInternal))
defer span.End() defer span.End()

View File

@ -46,7 +46,7 @@ func newServerMetricsSemConv(ctx context.Context, semConvMetricRegistry *metrics
} }
func (e *semConvServerMetrics) ServeHTTP(rw http.ResponseWriter, req *http.Request) { func (e *semConvServerMetrics) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
if e.semConvMetricRegistry == nil || e.semConvMetricRegistry.HTTPServerRequestDuration() == nil { if e.semConvMetricRegistry == nil || e.semConvMetricRegistry.HTTPServerRequestDuration() == nil || !SemConvMetricsEnabled(req.Context()) {
e.next.ServeHTTP(rw, req) e.next.ServeHTTP(rw, req)
return return
} }

View File

@ -83,6 +83,11 @@ func TestSemConvServerMetrics(t *testing.T) {
handler, err = capture.Wrap(handler) handler, err = capture.Wrap(handler)
require.NoError(t, err) require.NoError(t, err)
// Injection of the observability variables in the request context.
handler = WithObservabilityHandler(handler, Observability{
SemConvMetricsEnabled: true,
})
handler.ServeHTTP(rw, req) handler.ServeHTTP(rw, req)
got := metricdata.ResourceMetrics{} got := metricdata.ResourceMetrics{}

View File

@ -32,7 +32,7 @@ func NewService(ctx context.Context, service string, next http.Handler) http.Han
} }
func (t *serviceTracing) ServeHTTP(rw http.ResponseWriter, req *http.Request) { func (t *serviceTracing) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
if tracer := tracing.TracerFromContext(req.Context()); tracer != nil { if tracer := tracing.TracerFromContext(req.Context()); tracer != nil && DetailedTracingEnabled(req.Context()) {
tracingCtx, span := tracer.Start(req.Context(), "Service", trace.WithSpanKind(trace.SpanKindInternal)) tracingCtx, span := tracer.Start(req.Context(), "Service", trace.WithSpanKind(trace.SpanKindInternal))
defer span.End() defer span.End()

View File

@ -14,7 +14,6 @@ import (
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/traefik/traefik/v3/pkg/config/dynamic" "github.com/traefik/traefik/v3/pkg/config/dynamic"
"github.com/traefik/traefik/v3/pkg/middlewares" "github.com/traefik/traefik/v3/pkg/middlewares"
"go.opentelemetry.io/otel/trace"
) )
const typeName = "PassClientTLSCert" const typeName = "PassClientTLSCert"
@ -139,8 +138,8 @@ func New(ctx context.Context, next http.Handler, config dynamic.PassTLSClientCer
}, nil }, nil
} }
func (p *passTLSClientCert) GetTracingInformation() (string, string, trace.SpanKind) { func (p *passTLSClientCert) GetTracingInformation() (string, string) {
return p.name, typeName, trace.SpanKindInternal return p.name, typeName
} }
func (p *passTLSClientCert) ServeHTTP(rw http.ResponseWriter, req *http.Request) { func (p *passTLSClientCert) ServeHTTP(rw http.ResponseWriter, req *http.Request) {

View File

@ -14,7 +14,6 @@ import (
"github.com/traefik/traefik/v3/pkg/middlewares" "github.com/traefik/traefik/v3/pkg/middlewares"
"github.com/traefik/traefik/v3/pkg/middlewares/observability" "github.com/traefik/traefik/v3/pkg/middlewares/observability"
"github.com/vulcand/oxy/v2/utils" "github.com/vulcand/oxy/v2/utils"
"go.opentelemetry.io/otel/trace"
"golang.org/x/time/rate" "golang.org/x/time/rate"
) )
@ -127,8 +126,8 @@ func New(ctx context.Context, next http.Handler, config dynamic.RateLimit, name
}, nil }, nil
} }
func (rl *rateLimiter) GetTracingInformation() (string, string, trace.SpanKind) { func (rl *rateLimiter) GetTracingInformation() (string, string) {
return rl.name, typeName, trace.SpanKindInternal return rl.name, typeName
} }
func (rl *rateLimiter) ServeHTTP(rw http.ResponseWriter, req *http.Request) { func (rl *rateLimiter) ServeHTTP(rw http.ResponseWriter, req *http.Request) {

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