mirror of
https://github.com/containous/traefik.git
synced 2025-03-10 12:58:23 +03:00
OpenTelemetry Logs and Access Logs
Co-authored-by: Kevin Pollet <pollet.kevin@gmail.com>
This commit is contained in:
parent
33c1d700c0
commit
826a2b74aa
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
stdlog "log"
|
||||
"os"
|
||||
@ -20,12 +21,13 @@ func init() {
|
||||
zerolog.SetGlobalLevel(zerolog.ErrorLevel)
|
||||
}
|
||||
|
||||
func setupLogger(staticConfiguration *static.Configuration) {
|
||||
func setupLogger(staticConfiguration *static.Configuration) error {
|
||||
// configure log format
|
||||
w := getLogWriter(staticConfiguration)
|
||||
|
||||
// configure log level
|
||||
logLevel := getLogLevel(staticConfiguration)
|
||||
zerolog.SetGlobalLevel(logLevel)
|
||||
|
||||
// create logger
|
||||
logCtx := zerolog.New(w).With().Timestamp()
|
||||
@ -34,8 +36,16 @@ func setupLogger(staticConfiguration *static.Configuration) {
|
||||
}
|
||||
|
||||
log.Logger = logCtx.Logger().Level(logLevel)
|
||||
|
||||
if staticConfiguration.Log != nil && staticConfiguration.Log.OTLP != nil {
|
||||
var err error
|
||||
log.Logger, err = logs.SetupOTelLogger(log.Logger, staticConfiguration.Log.OTLP)
|
||||
if err != nil {
|
||||
return fmt.Errorf("setting up OpenTelemetry logger: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
zerolog.DefaultContextLogger = &log.Logger
|
||||
zerolog.SetGlobalLevel(logLevel)
|
||||
|
||||
// Global logrus replacement (related to lib like go-rancher-metadata, docker, etc.)
|
||||
logrus.StandardLogger().Out = logs.NoLevel(log.Logger, zerolog.DebugLevel)
|
||||
@ -43,11 +53,16 @@ func setupLogger(staticConfiguration *static.Configuration) {
|
||||
// configure default standard log.
|
||||
stdlog.SetFlags(stdlog.Lshortfile | stdlog.LstdFlags)
|
||||
stdlog.SetOutput(logs.NoLevel(log.Logger, zerolog.DebugLevel))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getLogWriter(staticConfiguration *static.Configuration) io.Writer {
|
||||
var w io.Writer = os.Stdout
|
||||
if staticConfiguration.Log != nil && staticConfiguration.Log.OTLP != nil {
|
||||
return io.Discard
|
||||
}
|
||||
|
||||
var w io.Writer = os.Stdout
|
||||
if staticConfiguration.Log != nil && len(staticConfiguration.Log.FilePath) > 0 {
|
||||
_, _ = os.OpenFile(staticConfiguration.Log.FilePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0o666)
|
||||
w = &lumberjack.Logger{
|
||||
|
@ -90,7 +90,9 @@ Complete documentation is available at https://traefik.io`,
|
||||
}
|
||||
|
||||
func runCmd(staticConfiguration *static.Configuration) error {
|
||||
setupLogger(staticConfiguration)
|
||||
if err := setupLogger(staticConfiguration); err != nil {
|
||||
return fmt.Errorf("setting up logger: %w", err)
|
||||
}
|
||||
|
||||
http.DefaultTransport.(*http.Transport).Proxy = http.ProxyFromEnvironment
|
||||
|
||||
|
@ -167,3 +167,9 @@ Please refer to the Forwarded headers [documentation](../routing/entrypoints.md#
|
||||
|
||||
In `v3.3`, the `acme.dnsChallenge.delaybeforecheck` and `acme.dnsChallenge.disablepropagationcheck` options of the ACME certificate resolver are deprecated,
|
||||
please use respectively `acme.dnsChallenge.propagation.delayBeforeCheck` and `acme.dnsChallenge.propagation.disableAllChecks` options instead.
|
||||
|
||||
### Tracing Global Attributes
|
||||
|
||||
In `v3.3`, the `tracing.globalAttributes` option has been deprecated, please use the `tracing.resourceAttributes` option instead.
|
||||
The `tracing.globalAttributes` option is misleading as its name does not reflect the operation of adding resource attributes to be sent to the collector,
|
||||
and will be removed in the next major version.
|
||||
|
@ -30,7 +30,7 @@ accessLog: {}
|
||||
|
||||
_Optional, Default="false"_
|
||||
|
||||
Enables accessLogs for internal resources (e.g.: `ping@internal`).
|
||||
Enables access logs for internal resources (e.g.: `ping@internal`).
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
accesslog:
|
||||
@ -306,4 +306,401 @@ services:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
```
|
||||
|
||||
## OpenTelemetry
|
||||
|
||||
To enable the OpenTelemetry Logger for access logs:
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
accesslog:
|
||||
otlp: {}
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[accesslog.otlp]
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--accesslog.otlp=true
|
||||
```
|
||||
|
||||
!!! info "Default protocol"
|
||||
|
||||
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.
|
||||
|
||||
### HTTP configuration
|
||||
|
||||
_Optional_
|
||||
|
||||
This instructs the exporter to send access logs to the OpenTelemetry Collector using HTTP.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
accesslog:
|
||||
otlp:
|
||||
http: {}
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[accesslog.otlp.http]
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--accesslog.otlp.http=true
|
||||
```
|
||||
|
||||
#### `endpoint`
|
||||
|
||||
_Optional, Default="`https://localhost:4318/v1/logs`", Format="`<scheme>://<host>:<port><path>`"_
|
||||
|
||||
URL of the OpenTelemetry Collector to send access logs to.
|
||||
|
||||
!!! info "Insecure mode"
|
||||
|
||||
To disable TLS, use `http://` instead of `https://` in the `endpoint` configuration.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
accesslog:
|
||||
otlp:
|
||||
http:
|
||||
endpoint: https://collector:4318/v1/logs
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[accesslog.otlp.http]
|
||||
endpoint = "https://collector:4318/v1/logs"
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--accesslog.otlp.http.endpoint=https://collector:4318/v1/logs
|
||||
```
|
||||
|
||||
#### `headers`
|
||||
|
||||
_Optional, Default={}_
|
||||
|
||||
Additional headers sent with access logs by the exporter to the OpenTelemetry Collector.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
accesslog:
|
||||
otlp:
|
||||
http:
|
||||
headers:
|
||||
foo: bar
|
||||
baz: buz
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[accesslog.otlp.http.headers]
|
||||
foo = "bar"
|
||||
baz = "buz"
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--accesslog.otlp.http.headers.foo=bar --accesslog.otlp.http.headers.baz=buz
|
||||
```
|
||||
|
||||
#### `tls`
|
||||
|
||||
_Optional_
|
||||
|
||||
Defines the Client TLS configuration used by the exporter to send access logs to the OpenTelemetry Collector.
|
||||
|
||||
##### `ca`
|
||||
|
||||
_Optional_
|
||||
|
||||
`ca` is the path to the certificate authority used for the secure connection to the OpenTelemetry Collector,
|
||||
it defaults to the system bundle.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
accesslog:
|
||||
otlp:
|
||||
http:
|
||||
tls:
|
||||
ca: path/to/ca.crt
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[accesslog.otlp.http.tls]
|
||||
ca = "path/to/ca.crt"
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--accesslog.otlp.http.tls.ca=path/to/ca.crt
|
||||
```
|
||||
|
||||
##### `cert`
|
||||
|
||||
_Optional_
|
||||
|
||||
`cert` is the path to the public certificate used for the secure connection to the OpenTelemetry Collector.
|
||||
When using this option, setting the `key` option is required.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
accesslog:
|
||||
otlp:
|
||||
http:
|
||||
tls:
|
||||
cert: path/to/foo.cert
|
||||
key: path/to/foo.key
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[accesslog.otlp.http.tls]
|
||||
cert = "path/to/foo.cert"
|
||||
key = "path/to/foo.key"
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--accesslog.otlp.http.tls.cert=path/to/foo.cert
|
||||
--accesslog.otlp.http.tls.key=path/to/foo.key
|
||||
```
|
||||
|
||||
##### `key`
|
||||
|
||||
_Optional_
|
||||
|
||||
`key` is the path to the private key used for the secure connection to the OpenTelemetry Collector.
|
||||
When using this option, setting the `cert` option is required.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
accesslog:
|
||||
otlp:
|
||||
http:
|
||||
tls:
|
||||
cert: path/to/foo.cert
|
||||
key: path/to/foo.key
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[accesslog.otlp.http.tls]
|
||||
cert = "path/to/foo.cert"
|
||||
key = "path/to/foo.key"
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--accesslog.otlp.http.tls.cert=path/to/foo.cert
|
||||
--accesslog.otlp.http.tls.key=path/to/foo.key
|
||||
```
|
||||
|
||||
##### `insecureSkipVerify`
|
||||
|
||||
_Optional, Default=false_
|
||||
|
||||
If `insecureSkipVerify` is `true`,
|
||||
the TLS connection to the OpenTelemetry Collector accepts any certificate presented by the server regardless of the hostnames it covers.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
accesslog:
|
||||
otlp:
|
||||
http:
|
||||
tls:
|
||||
insecureSkipVerify: true
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[accesslog.otlp.http.tls]
|
||||
insecureSkipVerify = true
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--accesslog.otlp.http.tls.insecureSkipVerify=true
|
||||
```
|
||||
|
||||
### gRPC configuration
|
||||
|
||||
_Optional_
|
||||
|
||||
This instructs the exporter to send access logs to the OpenTelemetry Collector using gRPC.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
accesslog:
|
||||
otlp:
|
||||
grpc: {}
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[accesslog.otlp.grpc]
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--accesslog.otlp.grpc=true
|
||||
```
|
||||
|
||||
#### `endpoint`
|
||||
|
||||
_Required, Default="localhost:4317", Format="`<host>:<port>`"_
|
||||
|
||||
Address of the OpenTelemetry Collector to send access logs to.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
accesslog:
|
||||
otlp:
|
||||
grpc:
|
||||
endpoint: localhost:4317
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[accesslog.otlp.grpc]
|
||||
endpoint = "localhost:4317"
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--accesslog.otlp.grpc.endpoint=localhost:4317
|
||||
```
|
||||
|
||||
#### `insecure`
|
||||
|
||||
_Optional, Default=false_
|
||||
|
||||
Allows exporter to send access logs to the OpenTelemetry Collector without using a secured protocol.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
accesslog:
|
||||
otlp:
|
||||
grpc:
|
||||
insecure: true
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[accesslog.otlp.grpc]
|
||||
insecure = true
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--accesslog.otlp.grpc.insecure=true
|
||||
```
|
||||
|
||||
#### `headers`
|
||||
|
||||
_Optional, Default={}_
|
||||
|
||||
Additional headers sent with access logs by the exporter to the OpenTelemetry Collector.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
accesslog:
|
||||
otlp:
|
||||
grpc:
|
||||
headers:
|
||||
foo: bar
|
||||
baz: buz
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[accesslog.otlp.grpc.headers]
|
||||
foo = "bar"
|
||||
baz = "buz"
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--accesslog.otlp.grpc.headers.foo=bar --accesslog.otlp.grpc.headers.baz=buz
|
||||
```
|
||||
|
||||
#### `tls`
|
||||
|
||||
_Optional_
|
||||
|
||||
Defines the Client TLS configuration used by the exporter to send access logs to the OpenTelemetry Collector.
|
||||
|
||||
##### `ca`
|
||||
|
||||
_Optional_
|
||||
|
||||
`ca` is the path to the certificate authority used for the secure connection to the OpenTelemetry Collector,
|
||||
it defaults to the system bundle.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
accesslog:
|
||||
otlp:
|
||||
grpc:
|
||||
tls:
|
||||
ca: path/to/ca.crt
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[accesslog.otlp.grpc.tls]
|
||||
ca = "path/to/ca.crt"
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--accesslog.otlp.grpc.tls.ca=path/to/ca.crt
|
||||
```
|
||||
|
||||
##### `cert`
|
||||
|
||||
_Optional_
|
||||
|
||||
`cert` is the path to the public certificate used for the secure connection to the OpenTelemetry Collector.
|
||||
When using this option, setting the `key` option is required.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
accesslog:
|
||||
otlp:
|
||||
grpc:
|
||||
tls:
|
||||
cert: path/to/foo.cert
|
||||
key: path/to/foo.key
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[accesslog.otlp.grpc.tls]
|
||||
cert = "path/to/foo.cert"
|
||||
key = "path/to/foo.key"
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--accesslog.otlp.grpc.tls.cert=path/to/foo.cert
|
||||
--accesslog.otlp.grpc.tls.key=path/to/foo.key
|
||||
```
|
||||
|
||||
##### `key`
|
||||
|
||||
_Optional_
|
||||
|
||||
`key` is the path to the private key used for the secure connection to the OpenTelemetry Collector.
|
||||
When using this option, setting the `cert` option is required.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
accesslog:
|
||||
otlp:
|
||||
grpc:
|
||||
tls:
|
||||
cert: path/to/foo.cert
|
||||
key: path/to/foo.key
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[accesslog.otlp.grpc.tls]
|
||||
cert = "path/to/foo.cert"
|
||||
key = "path/to/foo.key"
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--accesslog.otlp.grpc.tls.cert=path/to/foo.cert
|
||||
--accesslog.otlp.grpc.tls.key=path/to/foo.key
|
||||
```
|
||||
|
||||
##### `insecureSkipVerify`
|
||||
|
||||
_Optional, Default=false_
|
||||
|
||||
If `insecureSkipVerify` is `true`,
|
||||
the TLS connection to the OpenTelemetry Collector accepts any certificate presented by the server regardless of the hostnames it covers.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
accesslog:
|
||||
otlp:
|
||||
grpc:
|
||||
tls:
|
||||
insecureSkipVerify: true
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[accesslog.otlp.grpc.tls]
|
||||
insecureSkipVerify = true
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--accesslog.otlp.grpc.tls.insecureSkipVerify=true
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
|
@ -181,4 +181,401 @@ log:
|
||||
--log.compress=true
|
||||
```
|
||||
|
||||
## OpenTelemetry
|
||||
|
||||
To enable the OpenTelemetry Logger for logs:
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
log:
|
||||
otlp: {}
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[log.otlp]
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--log.otlp=true
|
||||
```
|
||||
|
||||
!!! info "Default protocol"
|
||||
|
||||
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.
|
||||
|
||||
### HTTP configuration
|
||||
|
||||
_Optional_
|
||||
|
||||
This instructs the exporter to send logs to the OpenTelemetry Collector using HTTP.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
log:
|
||||
otlp:
|
||||
http: {}
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[log.otlp.http]
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--log.otlp.http=true
|
||||
```
|
||||
|
||||
#### `endpoint`
|
||||
|
||||
_Optional, Default="`https://localhost:4318/v1/logs`", Format="`<scheme>://<host>:<port><path>`"_
|
||||
|
||||
URL of the OpenTelemetry Collector to send logs to.
|
||||
|
||||
!!! info "Insecure mode"
|
||||
|
||||
To disable TLS, use `http://` instead of `https://` in the `endpoint` configuration.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
log:
|
||||
otlp:
|
||||
http:
|
||||
endpoint: https://collector:4318/v1/logs
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[log.otlp.http]
|
||||
endpoint = "https://collector:4318/v1/logs"
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--log.otlp.http.endpoint=https://collector:4318/v1/logs
|
||||
```
|
||||
|
||||
#### `headers`
|
||||
|
||||
_Optional, Default={}_
|
||||
|
||||
Additional headers sent with logs by the exporter to the OpenTelemetry Collector.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
log:
|
||||
otlp:
|
||||
http:
|
||||
headers:
|
||||
foo: bar
|
||||
baz: buz
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[log.otlp.http.headers]
|
||||
foo = "bar"
|
||||
baz = "buz"
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--log.otlp.http.headers.foo=bar --log.otlp.http.headers.baz=buz
|
||||
```
|
||||
|
||||
#### `tls`
|
||||
|
||||
_Optional_
|
||||
|
||||
Defines the Client TLS configuration used by the exporter to send logs to the OpenTelemetry Collector.
|
||||
|
||||
##### `ca`
|
||||
|
||||
_Optional_
|
||||
|
||||
`ca` is the path to the certificate authority used for the secure connection to the OpenTelemetry Collector,
|
||||
it defaults to the system bundle.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
log:
|
||||
otlp:
|
||||
http:
|
||||
tls:
|
||||
ca: path/to/ca.crt
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[log.otlp.http.tls]
|
||||
ca = "path/to/ca.crt"
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--log.otlp.http.tls.ca=path/to/ca.crt
|
||||
```
|
||||
|
||||
##### `cert`
|
||||
|
||||
_Optional_
|
||||
|
||||
`cert` is the path to the public certificate used for the secure connection to the OpenTelemetry Collector.
|
||||
When using this option, setting the `key` option is required.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
log:
|
||||
otlp:
|
||||
http:
|
||||
tls:
|
||||
cert: path/to/foo.cert
|
||||
key: path/to/foo.key
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[log.otlp.http.tls]
|
||||
cert = "path/to/foo.cert"
|
||||
key = "path/to/foo.key"
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--log.otlp.http.tls.cert=path/to/foo.cert
|
||||
--log.otlp.http.tls.key=path/to/foo.key
|
||||
```
|
||||
|
||||
##### `key`
|
||||
|
||||
_Optional_
|
||||
|
||||
`key` is the path to the private key used for the secure connection to the OpenTelemetry Collector.
|
||||
When using this option, setting the `cert` option is required.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
log:
|
||||
otlp:
|
||||
http:
|
||||
tls:
|
||||
cert: path/to/foo.cert
|
||||
key: path/to/foo.key
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[log.otlp.http.tls]
|
||||
cert = "path/to/foo.cert"
|
||||
key = "path/to/foo.key"
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--log.otlp.http.tls.cert=path/to/foo.cert
|
||||
--log.otlp.http.tls.key=path/to/foo.key
|
||||
```
|
||||
|
||||
##### `insecureSkipVerify`
|
||||
|
||||
_Optional, Default=false_
|
||||
|
||||
If `insecureSkipVerify` is `true`,
|
||||
the TLS connection to the OpenTelemetry Collector accepts any certificate presented by the server regardless of the hostnames it covers.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
log:
|
||||
otlp:
|
||||
http:
|
||||
tls:
|
||||
insecureSkipVerify: true
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[log.otlp.http.tls]
|
||||
insecureSkipVerify = true
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--log.otlp.http.tls.insecureSkipVerify=true
|
||||
```
|
||||
|
||||
### gRPC configuration
|
||||
|
||||
_Optional_
|
||||
|
||||
This instructs the exporter to send logs to the OpenTelemetry Collector using gRPC.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
log:
|
||||
otlp:
|
||||
grpc: {}
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[log.otlp.grpc]
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--log.otlp.grpc=true
|
||||
```
|
||||
|
||||
#### `endpoint`
|
||||
|
||||
_Required, Default="localhost:4317", Format="`<host>:<port>`"_
|
||||
|
||||
Address of the OpenTelemetry Collector to send logs to.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
log:
|
||||
otlp:
|
||||
grpc:
|
||||
endpoint: localhost:4317
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[log.otlp.grpc]
|
||||
endpoint = "localhost:4317"
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--log.otlp.grpc.endpoint=localhost:4317
|
||||
```
|
||||
|
||||
#### `insecure`
|
||||
|
||||
_Optional, Default=false_
|
||||
|
||||
Allows exporter to send logs to the OpenTelemetry Collector without using a secured protocol.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
log:
|
||||
otlp:
|
||||
grpc:
|
||||
insecure: true
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[log.otlp.grpc]
|
||||
insecure = true
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--log.otlp.grpc.insecure=true
|
||||
```
|
||||
|
||||
#### `headers`
|
||||
|
||||
_Optional, Default={}_
|
||||
|
||||
Additional headers sent with logs by the exporter to the OpenTelemetry Collector.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
log:
|
||||
otlp:
|
||||
grpc:
|
||||
headers:
|
||||
foo: bar
|
||||
baz: buz
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[log.otlp.grpc.headers]
|
||||
foo = "bar"
|
||||
baz = "buz"
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--log.otlp.grpc.headers.foo=bar --log.otlp.grpc.headers.baz=buz
|
||||
```
|
||||
|
||||
#### `tls`
|
||||
|
||||
_Optional_
|
||||
|
||||
Defines the Client TLS configuration used by the exporter to send logs to the OpenTelemetry Collector.
|
||||
|
||||
##### `ca`
|
||||
|
||||
_Optional_
|
||||
|
||||
`ca` is the path to the certificate authority used for the secure connection to the OpenTelemetry Collector,
|
||||
it defaults to the system bundle.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
log:
|
||||
otlp:
|
||||
grpc:
|
||||
tls:
|
||||
ca: path/to/ca.crt
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[log.otlp.grpc.tls]
|
||||
ca = "path/to/ca.crt"
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--log.otlp.grpc.tls.ca=path/to/ca.crt
|
||||
```
|
||||
|
||||
##### `cert`
|
||||
|
||||
_Optional_
|
||||
|
||||
`cert` is the path to the public certificate used for the secure connection to the OpenTelemetry Collector.
|
||||
When using this option, setting the `key` option is required.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
log:
|
||||
otlp:
|
||||
grpc:
|
||||
tls:
|
||||
cert: path/to/foo.cert
|
||||
key: path/to/foo.key
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[log.otlp.grpc.tls]
|
||||
cert = "path/to/foo.cert"
|
||||
key = "path/to/foo.key"
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--log.otlp.grpc.tls.cert=path/to/foo.cert
|
||||
--log.otlp.grpc.tls.key=path/to/foo.key
|
||||
```
|
||||
|
||||
##### `key`
|
||||
|
||||
_Optional_
|
||||
|
||||
`key` is the path to the private key used for the secure connection to the OpenTelemetry Collector.
|
||||
When using this option, setting the `cert` option is required.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
log:
|
||||
otlp:
|
||||
grpc:
|
||||
tls:
|
||||
cert: path/to/foo.cert
|
||||
key: path/to/foo.key
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[log.otlp.grpc.tls]
|
||||
cert = "path/to/foo.cert"
|
||||
key = "path/to/foo.key"
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--log.otlp.grpc.tls.cert=path/to/foo.cert
|
||||
--log.otlp.grpc.tls.key=path/to/foo.key
|
||||
```
|
||||
|
||||
##### `insecureSkipVerify`
|
||||
|
||||
_Optional, Default=false_
|
||||
|
||||
If `insecureSkipVerify` is `true`,
|
||||
the TLS connection to the OpenTelemetry Collector accepts any certificate presented by the server regardless of the hostnames it covers.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
log:
|
||||
otlp:
|
||||
grpc:
|
||||
tls:
|
||||
insecureSkipVerify: true
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[log.otlp.grpc.tls]
|
||||
insecureSkipVerify = true
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--log.otlp.grpc.tls.insecureSkipVerify=true
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
|
@ -23,7 +23,7 @@ metrics:
|
||||
|
||||
!!! info "Default protocol"
|
||||
|
||||
The OpenTelemetry exporter will export metrics to the collector using HTTP by default to https://localhost:4318/v1/metrics, see the [gRPC Section](#grpc-configuration) to use gRPC.
|
||||
The OpenTelemetry exporter will export metrics to the collector using HTTPS by default to https://localhost:4318/v1/metrics, see the [gRPC Section](#grpc-configuration) to use gRPC.
|
||||
|
||||
#### `addEntryPointsLabels`
|
||||
|
||||
@ -184,25 +184,29 @@ metrics:
|
||||
|
||||
#### `endpoint`
|
||||
|
||||
_Required, Default="http://localhost:4318/v1/metrics", Format="`<scheme>://<host>:<port><path>`"_
|
||||
_Optional, Default="https://localhost:4318/v1/metrics", Format="`<scheme>://<host>:<port><path>`"_
|
||||
|
||||
URL of the OpenTelemetry Collector to send metrics to.
|
||||
|
||||
!!! info "Insecure mode"
|
||||
|
||||
To disable TLS, use `http://` instead of `https://` in the `endpoint` configuration.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
metrics:
|
||||
otlp:
|
||||
http:
|
||||
endpoint: http://localhost:4318/v1/metrics
|
||||
endpoint: https://collector:4318/v1/metrics
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[metrics]
|
||||
[metrics.otlp.http]
|
||||
endpoint = "http://localhost:4318/v1/metrics"
|
||||
endpoint = "https://collector:4318/v1/metrics"
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--metrics.otlp.http.endpoint=http://localhost:4318/v1/metrics
|
||||
--metrics.otlp.http.endpoint=https://collector:4318/v1/metrics
|
||||
```
|
||||
|
||||
#### `headers`
|
||||
|
@ -25,7 +25,7 @@ tracing:
|
||||
|
||||
!!! info "Default protocol"
|
||||
|
||||
The OpenTelemetry trace exporter will export traces to the collector using HTTP by default to https://localhost:4318/v1/traces, see the [gRPC Section](#grpc-configuration) to use gRPC.
|
||||
The OpenTelemetry trace exporter will export traces to the collector using HTTPS by default to https://localhost:4318/v1/traces, see the [gRPC Section](#grpc-configuration) to use gRPC.
|
||||
|
||||
!!! info "Trace sampling"
|
||||
|
||||
@ -72,25 +72,29 @@ tracing:
|
||||
|
||||
#### `endpoint`
|
||||
|
||||
_Required, Default="http://localhost:4318/v1/traces", Format="`<scheme>://<host>:<port><path>`"_
|
||||
_Optional, Default="https://localhost:4318/v1/traces", Format="`<scheme>://<host>:<port><path>`"_
|
||||
|
||||
URL of the OpenTelemetry Collector to send spans to.
|
||||
|
||||
!!! info "Insecure mode"
|
||||
|
||||
To disable TLS, use `http://` instead of `https://` in the `endpoint` configuration.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
tracing:
|
||||
otlp:
|
||||
http:
|
||||
endpoint: http://localhost:4318/v1/traces
|
||||
endpoint: https://collector:4318/v1/traces
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[tracing]
|
||||
[tracing.otlp.http]
|
||||
endpoint = "http://localhost:4318/v1/traces"
|
||||
endpoint = "https://collector:4318/v1/traces"
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--tracing.otlp.http.endpoint=http://localhost:4318/v1/traces
|
||||
--tracing.otlp.http.endpoint=https://collector:4318/v1/traces
|
||||
```
|
||||
|
||||
#### `headers`
|
||||
|
@ -92,29 +92,29 @@ tracing:
|
||||
--tracing.sampleRate=0.2
|
||||
```
|
||||
|
||||
#### `globalAttributes`
|
||||
#### `resourceAttributes`
|
||||
|
||||
_Optional, Default=empty_
|
||||
|
||||
Applies a list of shared key:value attributes on all spans.
|
||||
Defines additional resource attributes to be sent to the collector.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
tracing:
|
||||
globalAttributes:
|
||||
resourceAttributes:
|
||||
attr1: foo
|
||||
attr2: bar
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[tracing]
|
||||
[tracing.globalAttributes]
|
||||
[tracing.resourceAttributes]
|
||||
attr1 = "foo"
|
||||
attr2 = "bar"
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
--tracing.globalAttributes.attr1=foo
|
||||
--tracing.globalAttributes.attr2=bar
|
||||
--tracing.resourceAttributes.attr1=foo
|
||||
--tracing.resourceAttributes.attr2=bar
|
||||
```
|
||||
|
||||
#### `capturedRequestHeaders`
|
||||
|
@ -39,6 +39,60 @@ Keep access logs with status codes in the specified range.
|
||||
`--accesslog.format`:
|
||||
Access log format: json | common (Default: ```common```)
|
||||
|
||||
`--accesslog.otlp`:
|
||||
Settings for OpenTelemetry. (Default: ```false```)
|
||||
|
||||
`--accesslog.otlp.grpc`:
|
||||
gRPC configuration for the OpenTelemetry collector. (Default: ```false```)
|
||||
|
||||
`--accesslog.otlp.grpc.endpoint`:
|
||||
Sets the gRPC endpoint (host:port) of the collector. (Default: ```localhost:4317```)
|
||||
|
||||
`--accesslog.otlp.grpc.headers.<name>`:
|
||||
Headers sent with payload.
|
||||
|
||||
`--accesslog.otlp.grpc.insecure`:
|
||||
Disables client transport security for the exporter. (Default: ```false```)
|
||||
|
||||
`--accesslog.otlp.grpc.tls.ca`:
|
||||
TLS CA
|
||||
|
||||
`--accesslog.otlp.grpc.tls.cert`:
|
||||
TLS cert
|
||||
|
||||
`--accesslog.otlp.grpc.tls.insecureskipverify`:
|
||||
TLS insecure skip verify (Default: ```false```)
|
||||
|
||||
`--accesslog.otlp.grpc.tls.key`:
|
||||
TLS key
|
||||
|
||||
`--accesslog.otlp.http`:
|
||||
HTTP configuration for the OpenTelemetry collector. (Default: ```false```)
|
||||
|
||||
`--accesslog.otlp.http.endpoint`:
|
||||
Sets the HTTP endpoint (scheme://host:port/path) of the collector. (Default: ```https://localhost:4318```)
|
||||
|
||||
`--accesslog.otlp.http.headers.<name>`:
|
||||
Headers sent with payload.
|
||||
|
||||
`--accesslog.otlp.http.tls.ca`:
|
||||
TLS CA
|
||||
|
||||
`--accesslog.otlp.http.tls.cert`:
|
||||
TLS cert
|
||||
|
||||
`--accesslog.otlp.http.tls.insecureskipverify`:
|
||||
TLS insecure skip verify (Default: ```false```)
|
||||
|
||||
`--accesslog.otlp.http.tls.key`:
|
||||
TLS key
|
||||
|
||||
`--accesslog.otlp.resourceattributes.<name>`:
|
||||
Defines additional resource attributes (key:value).
|
||||
|
||||
`--accesslog.otlp.servicename`:
|
||||
Set the name for this service. (Default: ```traefik```)
|
||||
|
||||
`--api`:
|
||||
Enable api/dashboard. (Default: ```false```)
|
||||
|
||||
@ -333,6 +387,60 @@ Maximum size in megabytes of the log file before it gets rotated. (Default: ```0
|
||||
`--log.nocolor`:
|
||||
When using the 'common' format, disables the colorized output. (Default: ```false```)
|
||||
|
||||
`--log.otlp`:
|
||||
Settings for OpenTelemetry. (Default: ```false```)
|
||||
|
||||
`--log.otlp.grpc`:
|
||||
gRPC configuration for the OpenTelemetry collector. (Default: ```false```)
|
||||
|
||||
`--log.otlp.grpc.endpoint`:
|
||||
Sets the gRPC endpoint (host:port) of the collector. (Default: ```localhost:4317```)
|
||||
|
||||
`--log.otlp.grpc.headers.<name>`:
|
||||
Headers sent with payload.
|
||||
|
||||
`--log.otlp.grpc.insecure`:
|
||||
Disables client transport security for the exporter. (Default: ```false```)
|
||||
|
||||
`--log.otlp.grpc.tls.ca`:
|
||||
TLS CA
|
||||
|
||||
`--log.otlp.grpc.tls.cert`:
|
||||
TLS cert
|
||||
|
||||
`--log.otlp.grpc.tls.insecureskipverify`:
|
||||
TLS insecure skip verify (Default: ```false```)
|
||||
|
||||
`--log.otlp.grpc.tls.key`:
|
||||
TLS key
|
||||
|
||||
`--log.otlp.http`:
|
||||
HTTP configuration for the OpenTelemetry collector. (Default: ```false```)
|
||||
|
||||
`--log.otlp.http.endpoint`:
|
||||
Sets the HTTP endpoint (scheme://host:port/path) of the collector. (Default: ```https://localhost:4318```)
|
||||
|
||||
`--log.otlp.http.headers.<name>`:
|
||||
Headers sent with payload.
|
||||
|
||||
`--log.otlp.http.tls.ca`:
|
||||
TLS CA
|
||||
|
||||
`--log.otlp.http.tls.cert`:
|
||||
TLS cert
|
||||
|
||||
`--log.otlp.http.tls.insecureskipverify`:
|
||||
TLS insecure skip verify (Default: ```false```)
|
||||
|
||||
`--log.otlp.http.tls.key`:
|
||||
TLS key
|
||||
|
||||
`--log.otlp.resourceattributes.<name>`:
|
||||
Defines additional resource attributes (key:value).
|
||||
|
||||
`--log.otlp.servicename`:
|
||||
Set the name for this service. (Default: ```traefik```)
|
||||
|
||||
`--metrics.addinternals`:
|
||||
Enables metrics for internal services (ping, dashboard, etc...). (Default: ```false```)
|
||||
|
||||
@ -1138,7 +1246,7 @@ Defines the allowed SPIFFE IDs (takes precedence over the SPIFFE TrustDomain).
|
||||
Defines the allowed SPIFFE trust domain.
|
||||
|
||||
`--tracing`:
|
||||
OpenTracing configuration. (Default: ```false```)
|
||||
Tracing configuration. (Default: ```false```)
|
||||
|
||||
`--tracing.addinternals`:
|
||||
Enables tracing for internal services (ping, dashboard, etc...). (Default: ```false```)
|
||||
@ -1150,7 +1258,7 @@ Request headers to add as attributes for server and client spans.
|
||||
Response headers to add as attributes for server and client spans.
|
||||
|
||||
`--tracing.globalattributes.<name>`:
|
||||
Defines additional attributes (key:value) on all spans.
|
||||
(Deprecated) Defines additional resource attributes (key:value).
|
||||
|
||||
`--tracing.otlp`:
|
||||
Settings for OpenTelemetry. (Default: ```false```)
|
||||
@ -1200,6 +1308,9 @@ TLS insecure skip verify (Default: ```false```)
|
||||
`--tracing.otlp.http.tls.key`:
|
||||
TLS key
|
||||
|
||||
`--tracing.resourceattributes.<name>`:
|
||||
Defines additional resource attributes (key:value).
|
||||
|
||||
`--tracing.safequeryparams`:
|
||||
Query params to not redact.
|
||||
|
||||
@ -1207,4 +1318,4 @@ Query params to not redact.
|
||||
Sets the rate between 0.0 and 1.0 of requests to trace. (Default: ```1.000000```)
|
||||
|
||||
`--tracing.servicename`:
|
||||
Set the name for this service. (Default: ```traefik```)
|
||||
Sets the name for this service. (Default: ```traefik```)
|
||||
|
@ -39,6 +39,60 @@ Keep access logs with status codes in the specified range.
|
||||
`TRAEFIK_ACCESSLOG_FORMAT`:
|
||||
Access log format: json | common (Default: ```common```)
|
||||
|
||||
`TRAEFIK_ACCESSLOG_OTLP`:
|
||||
Settings for OpenTelemetry. (Default: ```false```)
|
||||
|
||||
`TRAEFIK_ACCESSLOG_OTLP_GRPC`:
|
||||
gRPC configuration for the OpenTelemetry collector. (Default: ```false```)
|
||||
|
||||
`TRAEFIK_ACCESSLOG_OTLP_GRPC_ENDPOINT`:
|
||||
Sets the gRPC endpoint (host:port) of the collector. (Default: ```localhost:4317```)
|
||||
|
||||
`TRAEFIK_ACCESSLOG_OTLP_GRPC_HEADERS_<NAME>`:
|
||||
Headers sent with payload.
|
||||
|
||||
`TRAEFIK_ACCESSLOG_OTLP_GRPC_INSECURE`:
|
||||
Disables client transport security for the exporter. (Default: ```false```)
|
||||
|
||||
`TRAEFIK_ACCESSLOG_OTLP_GRPC_TLS_CA`:
|
||||
TLS CA
|
||||
|
||||
`TRAEFIK_ACCESSLOG_OTLP_GRPC_TLS_CERT`:
|
||||
TLS cert
|
||||
|
||||
`TRAEFIK_ACCESSLOG_OTLP_GRPC_TLS_INSECURESKIPVERIFY`:
|
||||
TLS insecure skip verify (Default: ```false```)
|
||||
|
||||
`TRAEFIK_ACCESSLOG_OTLP_GRPC_TLS_KEY`:
|
||||
TLS key
|
||||
|
||||
`TRAEFIK_ACCESSLOG_OTLP_HTTP`:
|
||||
HTTP configuration for the OpenTelemetry collector. (Default: ```false```)
|
||||
|
||||
`TRAEFIK_ACCESSLOG_OTLP_HTTP_ENDPOINT`:
|
||||
Sets the HTTP endpoint (scheme://host:port/path) of the collector. (Default: ```https://localhost:4318```)
|
||||
|
||||
`TRAEFIK_ACCESSLOG_OTLP_HTTP_HEADERS_<NAME>`:
|
||||
Headers sent with payload.
|
||||
|
||||
`TRAEFIK_ACCESSLOG_OTLP_HTTP_TLS_CA`:
|
||||
TLS CA
|
||||
|
||||
`TRAEFIK_ACCESSLOG_OTLP_HTTP_TLS_CERT`:
|
||||
TLS cert
|
||||
|
||||
`TRAEFIK_ACCESSLOG_OTLP_HTTP_TLS_INSECURESKIPVERIFY`:
|
||||
TLS insecure skip verify (Default: ```false```)
|
||||
|
||||
`TRAEFIK_ACCESSLOG_OTLP_HTTP_TLS_KEY`:
|
||||
TLS key
|
||||
|
||||
`TRAEFIK_ACCESSLOG_OTLP_RESOURCEATTRIBUTES_<NAME>`:
|
||||
Defines additional resource attributes (key:value).
|
||||
|
||||
`TRAEFIK_ACCESSLOG_OTLP_SERVICENAME`:
|
||||
Set the name for this service. (Default: ```traefik```)
|
||||
|
||||
`TRAEFIK_API`:
|
||||
Enable api/dashboard. (Default: ```false```)
|
||||
|
||||
@ -333,6 +387,60 @@ Maximum size in megabytes of the log file before it gets rotated. (Default: ```0
|
||||
`TRAEFIK_LOG_NOCOLOR`:
|
||||
When using the 'common' format, disables the colorized output. (Default: ```false```)
|
||||
|
||||
`TRAEFIK_LOG_OTLP`:
|
||||
Settings for OpenTelemetry. (Default: ```false```)
|
||||
|
||||
`TRAEFIK_LOG_OTLP_GRPC`:
|
||||
gRPC configuration for the OpenTelemetry collector. (Default: ```false```)
|
||||
|
||||
`TRAEFIK_LOG_OTLP_GRPC_ENDPOINT`:
|
||||
Sets the gRPC endpoint (host:port) of the collector. (Default: ```localhost:4317```)
|
||||
|
||||
`TRAEFIK_LOG_OTLP_GRPC_HEADERS_<NAME>`:
|
||||
Headers sent with payload.
|
||||
|
||||
`TRAEFIK_LOG_OTLP_GRPC_INSECURE`:
|
||||
Disables client transport security for the exporter. (Default: ```false```)
|
||||
|
||||
`TRAEFIK_LOG_OTLP_GRPC_TLS_CA`:
|
||||
TLS CA
|
||||
|
||||
`TRAEFIK_LOG_OTLP_GRPC_TLS_CERT`:
|
||||
TLS cert
|
||||
|
||||
`TRAEFIK_LOG_OTLP_GRPC_TLS_INSECURESKIPVERIFY`:
|
||||
TLS insecure skip verify (Default: ```false```)
|
||||
|
||||
`TRAEFIK_LOG_OTLP_GRPC_TLS_KEY`:
|
||||
TLS key
|
||||
|
||||
`TRAEFIK_LOG_OTLP_HTTP`:
|
||||
HTTP configuration for the OpenTelemetry collector. (Default: ```false```)
|
||||
|
||||
`TRAEFIK_LOG_OTLP_HTTP_ENDPOINT`:
|
||||
Sets the HTTP endpoint (scheme://host:port/path) of the collector. (Default: ```https://localhost:4318```)
|
||||
|
||||
`TRAEFIK_LOG_OTLP_HTTP_HEADERS_<NAME>`:
|
||||
Headers sent with payload.
|
||||
|
||||
`TRAEFIK_LOG_OTLP_HTTP_TLS_CA`:
|
||||
TLS CA
|
||||
|
||||
`TRAEFIK_LOG_OTLP_HTTP_TLS_CERT`:
|
||||
TLS cert
|
||||
|
||||
`TRAEFIK_LOG_OTLP_HTTP_TLS_INSECURESKIPVERIFY`:
|
||||
TLS insecure skip verify (Default: ```false```)
|
||||
|
||||
`TRAEFIK_LOG_OTLP_HTTP_TLS_KEY`:
|
||||
TLS key
|
||||
|
||||
`TRAEFIK_LOG_OTLP_RESOURCEATTRIBUTES_<NAME>`:
|
||||
Defines additional resource attributes (key:value).
|
||||
|
||||
`TRAEFIK_LOG_OTLP_SERVICENAME`:
|
||||
Set the name for this service. (Default: ```traefik```)
|
||||
|
||||
`TRAEFIK_METRICS_ADDINTERNALS`:
|
||||
Enables metrics for internal services (ping, dashboard, etc...). (Default: ```false```)
|
||||
|
||||
@ -1138,7 +1246,7 @@ Defines the allowed SPIFFE IDs (takes precedence over the SPIFFE TrustDomain).
|
||||
Defines the allowed SPIFFE trust domain.
|
||||
|
||||
`TRAEFIK_TRACING`:
|
||||
OpenTracing configuration. (Default: ```false```)
|
||||
Tracing configuration. (Default: ```false```)
|
||||
|
||||
`TRAEFIK_TRACING_ADDINTERNALS`:
|
||||
Enables tracing for internal services (ping, dashboard, etc...). (Default: ```false```)
|
||||
@ -1150,7 +1258,7 @@ Request headers to add as attributes for server and client spans.
|
||||
Response headers to add as attributes for server and client spans.
|
||||
|
||||
`TRAEFIK_TRACING_GLOBALATTRIBUTES_<NAME>`:
|
||||
Defines additional attributes (key:value) on all spans.
|
||||
(Deprecated) Defines additional resource attributes (key:value).
|
||||
|
||||
`TRAEFIK_TRACING_OTLP`:
|
||||
Settings for OpenTelemetry. (Default: ```false```)
|
||||
@ -1200,6 +1308,9 @@ TLS insecure skip verify (Default: ```false```)
|
||||
`TRAEFIK_TRACING_OTLP_HTTP_TLS_KEY`:
|
||||
TLS key
|
||||
|
||||
`TRAEFIK_TRACING_RESOURCEATTRIBUTES_<NAME>`:
|
||||
Defines additional resource attributes (key:value).
|
||||
|
||||
`TRAEFIK_TRACING_SAFEQUERYPARAMS`:
|
||||
Query params to not redact.
|
||||
|
||||
@ -1207,4 +1318,4 @@ Query params to not redact.
|
||||
Sets the rate between 0.0 and 1.0 of requests to trace. (Default: ```1.000000```)
|
||||
|
||||
`TRAEFIK_TRACING_SERVICENAME`:
|
||||
Set the name for this service. (Default: ```traefik```)
|
||||
Sets the name for this service. (Default: ```traefik```)
|
||||
|
@ -381,6 +381,32 @@
|
||||
maxAge = 42
|
||||
maxBackups = 42
|
||||
compress = true
|
||||
[log.otlp]
|
||||
serviceName = "foobar"
|
||||
[log.otlp.resourceAttributes]
|
||||
name0 = "foobar"
|
||||
name1 = "foobar"
|
||||
[log.otlp.grpc]
|
||||
endpoint = "foobar"
|
||||
insecure = true
|
||||
[log.otlp.grpc.tls]
|
||||
ca = "foobar"
|
||||
cert = "foobar"
|
||||
key = "foobar"
|
||||
insecureSkipVerify = true
|
||||
[log.otlp.grpc.headers]
|
||||
name0 = "foobar"
|
||||
name1 = "foobar"
|
||||
[log.otlp.http]
|
||||
endpoint = "foobar"
|
||||
[log.otlp.http.tls]
|
||||
ca = "foobar"
|
||||
cert = "foobar"
|
||||
key = "foobar"
|
||||
insecureSkipVerify = true
|
||||
[log.otlp.http.headers]
|
||||
name0 = "foobar"
|
||||
name1 = "foobar"
|
||||
|
||||
[accessLog]
|
||||
filePath = "foobar"
|
||||
@ -401,6 +427,32 @@
|
||||
[accessLog.fields.headers.names]
|
||||
name0 = "foobar"
|
||||
name1 = "foobar"
|
||||
[accessLog.otlp]
|
||||
serviceName = "foobar"
|
||||
[accessLog.otlp.resourceAttributes]
|
||||
name0 = "foobar"
|
||||
name1 = "foobar"
|
||||
[accessLog.otlp.grpc]
|
||||
endpoint = "foobar"
|
||||
insecure = true
|
||||
[accessLog.otlp.grpc.tls]
|
||||
ca = "foobar"
|
||||
cert = "foobar"
|
||||
key = "foobar"
|
||||
insecureSkipVerify = true
|
||||
[accessLog.otlp.grpc.headers]
|
||||
name0 = "foobar"
|
||||
name1 = "foobar"
|
||||
[accessLog.otlp.http]
|
||||
endpoint = "foobar"
|
||||
[accessLog.otlp.http.tls]
|
||||
ca = "foobar"
|
||||
cert = "foobar"
|
||||
key = "foobar"
|
||||
insecureSkipVerify = true
|
||||
[accessLog.otlp.http.headers]
|
||||
name0 = "foobar"
|
||||
name1 = "foobar"
|
||||
|
||||
[tracing]
|
||||
serviceName = "foobar"
|
||||
@ -409,7 +461,7 @@
|
||||
safeQueryParams = ["foobar", "foobar"]
|
||||
sampleRate = 42.0
|
||||
addInternals = true
|
||||
[tracing.globalAttributes]
|
||||
[tracing.resourceAttributes]
|
||||
name0 = "foobar"
|
||||
name1 = "foobar"
|
||||
[tracing.otlp]
|
||||
@ -434,6 +486,9 @@
|
||||
[tracing.otlp.http.headers]
|
||||
name0 = "foobar"
|
||||
name1 = "foobar"
|
||||
[tracing.globalAttributes]
|
||||
name0 = "foobar"
|
||||
name1 = "foobar"
|
||||
|
||||
[hostResolver]
|
||||
cnameFlattening = true
|
||||
|
@ -418,6 +418,32 @@ log:
|
||||
maxAge: 42
|
||||
maxBackups: 42
|
||||
compress: true
|
||||
otlp:
|
||||
serviceName: foobar
|
||||
resourceAttributes:
|
||||
name0: foobar
|
||||
name1: foobar
|
||||
grpc:
|
||||
endpoint: foobar
|
||||
insecure: true
|
||||
tls:
|
||||
ca: foobar
|
||||
cert: foobar
|
||||
key: foobar
|
||||
insecureSkipVerify: true
|
||||
headers:
|
||||
name0: foobar
|
||||
name1: foobar
|
||||
http:
|
||||
endpoint: foobar
|
||||
tls:
|
||||
ca: foobar
|
||||
cert: foobar
|
||||
key: foobar
|
||||
insecureSkipVerify: true
|
||||
headers:
|
||||
name0: foobar
|
||||
name1: foobar
|
||||
accessLog:
|
||||
filePath: foobar
|
||||
format: foobar
|
||||
@ -439,9 +465,35 @@ accessLog:
|
||||
name1: foobar
|
||||
bufferingSize: 42
|
||||
addInternals: true
|
||||
otlp:
|
||||
serviceName: foobar
|
||||
resourceAttributes:
|
||||
name0: foobar
|
||||
name1: foobar
|
||||
grpc:
|
||||
endpoint: foobar
|
||||
insecure: true
|
||||
tls:
|
||||
ca: foobar
|
||||
cert: foobar
|
||||
key: foobar
|
||||
insecureSkipVerify: true
|
||||
headers:
|
||||
name0: foobar
|
||||
name1: foobar
|
||||
http:
|
||||
endpoint: foobar
|
||||
tls:
|
||||
ca: foobar
|
||||
cert: foobar
|
||||
key: foobar
|
||||
insecureSkipVerify: true
|
||||
headers:
|
||||
name0: foobar
|
||||
name1: foobar
|
||||
tracing:
|
||||
serviceName: foobar
|
||||
globalAttributes:
|
||||
resourceAttributes:
|
||||
name0: foobar
|
||||
name1: foobar
|
||||
capturedRequestHeaders:
|
||||
@ -477,6 +529,9 @@ tracing:
|
||||
headers:
|
||||
name0: foobar
|
||||
name1: foobar
|
||||
globalAttributes:
|
||||
name0: foobar
|
||||
name1: foobar
|
||||
hostResolver:
|
||||
cnameFlattening: true
|
||||
resolvConfig: foobar
|
||||
|
27
go.mod
27
go.mod
@ -51,7 +51,7 @@ require (
|
||||
github.com/prometheus/client_golang v1.19.1
|
||||
github.com/prometheus/client_model v0.6.1
|
||||
github.com/quic-go/quic-go v0.47.0
|
||||
github.com/rs/zerolog v1.29.0
|
||||
github.com/rs/zerolog v1.33.0
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/spiffe/go-spiffe/v2 v2.1.1
|
||||
github.com/stealthrocket/wasi-go v0.8.0
|
||||
@ -72,23 +72,28 @@ require (
|
||||
github.com/vulcand/oxy/v2 v2.0.0
|
||||
github.com/vulcand/predicate v1.2.0
|
||||
go.opentelemetry.io/collector/pdata v1.10.0
|
||||
go.opentelemetry.io/contrib/bridges/otellogrus v0.7.0
|
||||
go.opentelemetry.io/contrib/propagators/autoprop v0.53.0
|
||||
go.opentelemetry.io/otel v1.29.0
|
||||
go.opentelemetry.io/otel v1.32.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.8.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.8.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.28.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0
|
||||
go.opentelemetry.io/otel/metric v1.29.0
|
||||
go.opentelemetry.io/otel/sdk v1.28.0
|
||||
go.opentelemetry.io/otel/log v0.8.0
|
||||
go.opentelemetry.io/otel/metric v1.32.0
|
||||
go.opentelemetry.io/otel/sdk v1.32.0
|
||||
go.opentelemetry.io/otel/sdk/log v0.8.0
|
||||
go.opentelemetry.io/otel/sdk/metric v1.28.0
|
||||
go.opentelemetry.io/otel/trace v1.29.0
|
||||
go.opentelemetry.io/otel/trace v1.32.0
|
||||
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // No tag on the repo.
|
||||
golang.org/x/mod v0.21.0
|
||||
golang.org/x/net v0.30.0
|
||||
golang.org/x/sync v0.8.0
|
||||
golang.org/x/sys v0.26.0
|
||||
golang.org/x/text v0.19.0
|
||||
golang.org/x/sync v0.9.0
|
||||
golang.org/x/sys v0.27.0
|
||||
golang.org/x/text v0.20.0
|
||||
golang.org/x/time v0.7.0
|
||||
golang.org/x/tools v0.25.0
|
||||
google.golang.org/grpc v1.67.1
|
||||
@ -219,7 +224,7 @@ require (
|
||||
github.com/gophercloud/gophercloud v1.14.1 // indirect
|
||||
github.com/gophercloud/utils v0.0.0-20231010081019-80377eca5d56 // indirect
|
||||
github.com/gravitational/trace v1.1.16-0.20220114165159-14a9a7dd6aaf // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0 // indirect
|
||||
github.com/hashicorp/cronexpr v1.1.2 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
@ -364,8 +369,8 @@ require (
|
||||
golang.org/x/term v0.25.0 // indirect
|
||||
google.golang.org/api v0.204.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241104194629-dd2ea8efbc28 // indirect
|
||||
google.golang.org/protobuf v1.35.1 // indirect
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||
gopkg.in/h2non/gock.v1 v1.0.16 // indirect
|
||||
|
63
go.sum
63
go.sum
@ -262,7 +262,6 @@ github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03V
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
@ -576,8 +575,8 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmg
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0 h1:ad0vkEBuk23VJzZR9nkLVG0YAoN9coASF1GusYX6AlU=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0/go.mod h1:igFoXX2ELCW06bol23DWPB5BEWfZISOzSP5K2sbLea0=
|
||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
|
||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
|
||||
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
||||
@ -818,6 +817,7 @@ github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOA
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
@ -1046,13 +1046,13 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
|
||||
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
|
||||
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/rs/zerolog v1.29.0 h1:Zes4hju04hjbvkVkOhdl2HpZa+0PmVwigmo8XoORE5w=
|
||||
github.com/rs/zerolog v1.29.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0=
|
||||
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
|
||||
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/sacloud/api-client-go v0.2.10 h1:+rv3jDohD+pkdYwOTBiB+jZsM0xK3AxadXRzhp3q66c=
|
||||
@ -1288,6 +1288,8 @@ go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||
go.opentelemetry.io/collector/pdata v1.10.0 h1:oLyPLGvPTQrcRT64ZVruwvmH/u3SHTfNo01pteS4WOE=
|
||||
go.opentelemetry.io/collector/pdata v1.10.0/go.mod h1:IHxHsp+Jq/xfjORQMDJjSH6jvedOSTOyu3nbxqhWSYE=
|
||||
go.opentelemetry.io/contrib/bridges/otellogrus v0.7.0 h1:vPSzn6dQvdPq9ZiXFs+jUSJnzoKJkADD9yBdx/a1WgI=
|
||||
go.opentelemetry.io/contrib/bridges/otellogrus v0.7.0/go.mod h1:yZFNJIjn97IBhuMB3tTGPti9xasYLIdh3ChZIzyhz8A=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8=
|
||||
go.opentelemetry.io/contrib/propagators/autoprop v0.53.0 h1:4zaVLcJ5mvYw0vlk63TX62qS4qty/4jAY1BKZ1usu18=
|
||||
@ -1300,8 +1302,12 @@ go.opentelemetry.io/contrib/propagators/jaeger v1.28.0 h1:xQ3ktSVS128JWIaN1DiPGI
|
||||
go.opentelemetry.io/contrib/propagators/jaeger v1.28.0/go.mod h1:O9HIyI2kVBrFoEwQZ0IN6PHXykGoit4mZV2aEjkTRH4=
|
||||
go.opentelemetry.io/contrib/propagators/ot v1.28.0 h1:rmlG+2pc5k5M7Y7izDrxAHZUIwDERdGMTD9oMV7llMk=
|
||||
go.opentelemetry.io/contrib/propagators/ot v1.28.0/go.mod h1:MNgXIn+UrMbNGpd7xyckyo2LCHIgCdmdjEE7YNZGG+w=
|
||||
go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw=
|
||||
go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8=
|
||||
go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U=
|
||||
go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.8.0 h1:WzNab7hOOLzdDF/EoWCt4glhrbMPVMOO5JYTmpz36Ls=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.8.0/go.mod h1:hKvJwTzJdp90Vh7p6q/9PAOd55dI6WA6sWj62a/JvSs=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.8.0 h1:S+LdBGiQXtJdowoJoQPEtI52syEP/JYBUpjO49EQhV8=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.8.0/go.mod h1:5KXybFvPGds3QinJWQT7pmXf+TN5YIa7CNYObWRkj50=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0 h1:U2guen0GhqH8o/G2un8f/aG/y++OuW6MyCo6hT9prXk=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0/go.mod h1:yeGZANgEcpdx/WK0IvvRFC+2oLiMS2u4L/0Rj2M2Qr0=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.28.0 h1:aLmmtjRke7LPDQ3lvpFz+kNEH43faFhzW7v8BFIEydg=
|
||||
@ -1312,14 +1318,18 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 h1:R3X6Z
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0/go.mod h1:QWFXnDavXWwMx2EEcZsf3yxgEKAqsxQ+Syjp+seyInw=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0 h1:j9+03ymgYhPKmeXGk5Zu+cIZOlVzd9Zv7QIiyItjFBU=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0/go.mod h1:Y5+XiUG4Emn1hTfciPzGPJaSI+RpDts6BnCIir0SLqk=
|
||||
go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc=
|
||||
go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8=
|
||||
go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE=
|
||||
go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg=
|
||||
go.opentelemetry.io/otel/log v0.8.0 h1:egZ8vV5atrUWUbnSsHn6vB8R21G2wrKqNiDt3iWertk=
|
||||
go.opentelemetry.io/otel/log v0.8.0/go.mod h1:M9qvDdUTRCopJcGRKg57+JSQ9LgLBrwwfC32epk5NX8=
|
||||
go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M=
|
||||
go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8=
|
||||
go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4=
|
||||
go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU=
|
||||
go.opentelemetry.io/otel/sdk/log v0.8.0 h1:zg7GUYXqxk1jnGF/dTdLPrK06xJdrXgqgFLnI4Crxvs=
|
||||
go.opentelemetry.io/otel/sdk/log v0.8.0/go.mod h1:50iXr0UVwQrYS45KbruFrEt4LvAdCaWWgIrsN3ZQggo=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.28.0 h1:OkuaKgKrgAbYrrY0t92c+cC+2F6hsFNnCQArXCKlg08=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.28.0/go.mod h1:cWPjykihLAPvXKi4iZc1dpER3Jdq2Z0YLse3moQUCpg=
|
||||
go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4=
|
||||
go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ=
|
||||
go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM=
|
||||
go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
|
||||
go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
|
||||
@ -1508,8 +1518,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
|
||||
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@ -1597,11 +1607,12 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
|
||||
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
|
||||
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
@ -1631,8 +1642,8 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
|
||||
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
|
||||
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@ -1770,10 +1781,10 @@ google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxH
|
||||
google.golang.org/genproto v0.0.0-20210917145530-b395a37504d4/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 h1:Q3nlH8iSQSRUwOskjbcSMcF2jiYMNiQYZ0c2KEJLKKU=
|
||||
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38/go.mod h1:xBI+tzfqGGN2JBeSebfKXFSdBpWVQ7sLW40PTupVRm4=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53 h1:fVoAXEKA4+yufmbdVYv+SE73+cPZbbbe8paLsHfkK+U=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53/go.mod h1:riSXTwQ4+nqmPGtobMFyW5FqVAmIs0St6VPp4Ug7CE4=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 h1:zciRKQ4kBpFgpfC5QQCVtnnNAcLIqweL7plyZRQHVpI=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28 h1:M0KvPgPmDZHPlbRbaNU1APr28TvwvvdUPlSv7PUvy8g=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28/go.mod h1:dguCy7UOdZhTvLzDyt15+rOrawrpM4q7DD9dQ1P11P4=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241104194629-dd2ea8efbc28 h1:XVhgTWWV3kGQlwJHR3upFWZeTsei6Oks1apkZSeonIE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241104194629-dd2ea8efbc28/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
|
@ -502,14 +502,17 @@ func (e *experimental) deprecationNotice(logger zerolog.Logger) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
type tracing struct {
|
||||
SpanNameLimit *int `json:"spanNameLimit,omitempty" toml:"spanNameLimit,omitempty" yaml:"spanNameLimit,omitempty"`
|
||||
Jaeger map[string]any `json:"jaeger,omitempty" toml:"jaeger,omitempty" yaml:"jaeger,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||
Zipkin map[string]any `json:"zipkin,omitempty" toml:"zipkin,omitempty" yaml:"zipkin,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||
Datadog map[string]any `json:"datadog,omitempty" toml:"datadog,omitempty" yaml:"datadog,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||
Instana map[string]any `json:"instana,omitempty" toml:"instana,omitempty" yaml:"instana,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||
Haystack map[string]any `json:"haystack,omitempty" toml:"haystack,omitempty" yaml:"haystack,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||
Elastic map[string]any `json:"elastic,omitempty" toml:"elastic,omitempty" yaml:"elastic,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||
SpanNameLimit *int `json:"spanNameLimit,omitempty" toml:"spanNameLimit,omitempty" yaml:"spanNameLimit,omitempty"`
|
||||
GlobalAttributes map[string]string `json:"globalAttributes,omitempty" toml:"globalAttributes,omitempty" yaml:"globalAttributes,omitempty" export:"true"`
|
||||
Jaeger map[string]any `json:"jaeger,omitempty" toml:"jaeger,omitempty" yaml:"jaeger,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||
Zipkin map[string]any `json:"zipkin,omitempty" toml:"zipkin,omitempty" yaml:"zipkin,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||
Datadog map[string]any `json:"datadog,omitempty" toml:"datadog,omitempty" yaml:"datadog,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||
Instana map[string]any `json:"instana,omitempty" toml:"instana,omitempty" yaml:"instana,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||
Haystack map[string]any `json:"haystack,omitempty" toml:"haystack,omitempty" yaml:"haystack,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||
Elastic map[string]any `json:"elastic,omitempty" toml:"elastic,omitempty" yaml:"elastic,omitempty" label:"allowEmpty" file:"allowEmpty"`
|
||||
}
|
||||
|
||||
func (t *tracing) deprecationNotice(logger zerolog.Logger) bool {
|
||||
@ -523,6 +526,14 @@ func (t *tracing) deprecationNotice(logger zerolog.Logger) bool {
|
||||
"For more information please read the migration guide: https://doc.traefik.io/traefik/v3.2/migration/v2-to-v3/#tracing")
|
||||
}
|
||||
|
||||
if t.GlobalAttributes != nil {
|
||||
log.Warn().Msgf("tracing.globalAttributes option is now deprecated, please use tracing.resourceAttributes instead.")
|
||||
|
||||
logger.Error().Msg("`tracing.globalAttributes` option has been deprecated in v3.3, and will be removed in the next major version." +
|
||||
"Please use the `tracing.resourceAttributes` option instead." +
|
||||
"For more information please read the migration guide: https://doc.traefik.io/traefik/v3.3/migration/v3/#tracing-global-attributes")
|
||||
}
|
||||
|
||||
if t.Jaeger != nil {
|
||||
incompatible = true
|
||||
logger.Error().Msg("Jaeger Tracing backend has been removed in v3, please remove all Jaeger-related Tracing static configuration for Traefik to start." +
|
||||
|
@ -28,7 +28,6 @@ import (
|
||||
"github.com/traefik/traefik/v3/pkg/provider/kv/zk"
|
||||
"github.com/traefik/traefik/v3/pkg/provider/nomad"
|
||||
"github.com/traefik/traefik/v3/pkg/provider/rest"
|
||||
"github.com/traefik/traefik/v3/pkg/tracing/opentelemetry"
|
||||
"github.com/traefik/traefik/v3/pkg/types"
|
||||
)
|
||||
|
||||
@ -69,7 +68,7 @@ type Configuration struct {
|
||||
|
||||
Log *types.TraefikLog `description:"Traefik log settings." json:"log,omitempty" toml:"log,omitempty" yaml:"log,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
||||
AccessLog *types.AccessLog `description:"Access log settings." json:"accessLog,omitempty" toml:"accessLog,omitempty" yaml:"accessLog,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
||||
Tracing *Tracing `description:"OpenTracing configuration." json:"tracing,omitempty" toml:"tracing,omitempty" yaml:"tracing,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
||||
Tracing *Tracing `description:"Tracing configuration." json:"tracing,omitempty" toml:"tracing,omitempty" yaml:"tracing,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
||||
|
||||
HostResolver *types.HostResolverConfig `description:"Enable CNAME Flattening." json:"hostResolver,omitempty" toml:"hostResolver,omitempty" yaml:"hostResolver,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
||||
|
||||
@ -200,15 +199,17 @@ func (a *LifeCycle) SetDefaults() {
|
||||
|
||||
// Tracing holds the tracing configuration.
|
||||
type Tracing struct {
|
||||
ServiceName string `description:"Set the name for this service." json:"serviceName,omitempty" toml:"serviceName,omitempty" yaml:"serviceName,omitempty" export:"true"`
|
||||
GlobalAttributes map[string]string `description:"Defines additional attributes (key:value) on all spans." json:"globalAttributes,omitempty" toml:"globalAttributes,omitempty" yaml:"globalAttributes,omitempty" export:"true"`
|
||||
CapturedRequestHeaders []string `description:"Request headers to add as attributes for server and client spans." json:"capturedRequestHeaders,omitempty" toml:"capturedRequestHeaders,omitempty" yaml:"capturedRequestHeaders,omitempty" export:"true"`
|
||||
CapturedResponseHeaders []string `description:"Response headers to add as attributes for server and client spans." json:"capturedResponseHeaders,omitempty" toml:"capturedResponseHeaders,omitempty" yaml:"capturedResponseHeaders,omitempty" export:"true"`
|
||||
SafeQueryParams []string `description:"Query params to not redact." json:"safeQueryParams,omitempty" toml:"safeQueryParams,omitempty" yaml:"safeQueryParams,omitempty" export:"true"`
|
||||
SampleRate float64 `description:"Sets the rate between 0.0 and 1.0 of requests to trace." json:"sampleRate,omitempty" toml:"sampleRate,omitempty" yaml:"sampleRate,omitempty" export:"true"`
|
||||
AddInternals bool `description:"Enables tracing for internal services (ping, dashboard, etc...)." json:"addInternals,omitempty" toml:"addInternals,omitempty" yaml:"addInternals,omitempty" export:"true"`
|
||||
ServiceName string `description:"Sets the name for this service." 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"`
|
||||
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"`
|
||||
SafeQueryParams []string `description:"Query params to not redact." json:"safeQueryParams,omitempty" toml:"safeQueryParams,omitempty" yaml:"safeQueryParams,omitempty" export:"true"`
|
||||
SampleRate float64 `description:"Sets the rate between 0.0 and 1.0 of requests to trace." json:"sampleRate,omitempty" toml:"sampleRate,omitempty" yaml:"sampleRate,omitempty" export:"true"`
|
||||
AddInternals bool `description:"Enables tracing for internal services (ping, dashboard, etc...)." json:"addInternals,omitempty" toml:"addInternals,omitempty" yaml:"addInternals,omitempty" export:"true"`
|
||||
OTLP *types.OTelTracing `description:"Settings for OpenTelemetry." json:"otlp,omitempty" toml:"otlp,omitempty" yaml:"otlp,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
||||
|
||||
OTLP *opentelemetry.Config `description:"Settings for OpenTelemetry." json:"otlp,omitempty" toml:"otlp,omitempty" yaml:"otlp,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
||||
// Deprecated: please use ResourceAttributes instead.
|
||||
GlobalAttributes map[string]string `description:"(Deprecated) Defines additional resource attributes (key:value)." json:"globalAttributes,omitempty" toml:"globalAttributes,omitempty" yaml:"globalAttributes,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// SetDefaults sets the default values.
|
||||
@ -216,7 +217,7 @@ func (t *Tracing) SetDefaults() {
|
||||
t.ServiceName = "traefik"
|
||||
t.SampleRate = 1.0
|
||||
|
||||
t.OTLP = &opentelemetry.Config{}
|
||||
t.OTLP = &types.OTelTracing{}
|
||||
t.OTLP.SetDefaults()
|
||||
}
|
||||
|
||||
@ -270,6 +271,10 @@ func (c *Configuration) SetEffectiveConfiguration() {
|
||||
}
|
||||
}
|
||||
|
||||
if c.Tracing != nil && c.Tracing.GlobalAttributes != nil && c.Tracing.ResourceAttributes == nil {
|
||||
c.Tracing.ResourceAttributes = c.Tracing.GlobalAttributes
|
||||
}
|
||||
|
||||
if c.Providers.Docker != nil {
|
||||
if c.Providers.Docker.HTTPClientTimeout < 0 {
|
||||
c.Providers.Docker.HTTPClientTimeout = 0
|
||||
@ -381,6 +386,18 @@ func (c *Configuration) ValidateConfiguration() error {
|
||||
}
|
||||
}
|
||||
|
||||
if c.AccessLog != nil && c.AccessLog.OTLP != nil {
|
||||
if c.AccessLog.OTLP.GRPC != nil && c.AccessLog.OTLP.GRPC.TLS != nil && c.AccessLog.OTLP.GRPC.Insecure {
|
||||
return errors.New("access logs OTLP GRPC: TLS and Insecure options are mutually exclusive")
|
||||
}
|
||||
}
|
||||
|
||||
if c.Log != nil && c.Log.OTLP != nil {
|
||||
if c.Log.OTLP.GRPC != nil && c.Log.OTLP.GRPC.TLS != nil && c.Log.OTLP.GRPC.Insecure {
|
||||
return errors.New("logs OTLP GRPC: TLS and Insecure options are mutually exclusive")
|
||||
}
|
||||
}
|
||||
|
||||
if c.Tracing != nil && c.Tracing.OTLP != nil {
|
||||
if c.Tracing.OTLP.GRPC != nil && c.Tracing.OTLP.GRPC.TLS != nil && c.Tracing.OTLP.GRPC.Insecure {
|
||||
return errors.New("tracing OTLP GRPC: TLS and Insecure options are mutually exclusive")
|
||||
|
120
pkg/logs/otel.go
Normal file
120
pkg/logs/otel.go
Normal file
@ -0,0 +1,120 @@
|
||||
package logs
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/traefik/traefik/v3/pkg/types"
|
||||
otellog "go.opentelemetry.io/otel/log"
|
||||
)
|
||||
|
||||
// SetupOTelLogger sets up the OpenTelemetry logger.
|
||||
func SetupOTelLogger(logger zerolog.Logger, config *types.OTelLog) (zerolog.Logger, error) {
|
||||
if config == nil {
|
||||
return logger, nil
|
||||
}
|
||||
|
||||
provider, err := config.NewLoggerProvider()
|
||||
if err != nil {
|
||||
return zerolog.Logger{}, fmt.Errorf("setting up OpenTelemetry logger provider: %w", err)
|
||||
}
|
||||
|
||||
return logger.Hook(&otelLoggerHook{logger: provider.Logger("traefik")}), nil
|
||||
}
|
||||
|
||||
// otelLoggerHook is a zerolog hook that forwards logs to OpenTelemetry.
|
||||
type otelLoggerHook struct {
|
||||
logger otellog.Logger
|
||||
}
|
||||
|
||||
// Run forwards the log message to OpenTelemetry.
|
||||
func (h *otelLoggerHook) Run(e *zerolog.Event, level zerolog.Level, message string) {
|
||||
if level == zerolog.Disabled {
|
||||
return
|
||||
}
|
||||
|
||||
// Discard the event to avoid double logging.
|
||||
e.Discard()
|
||||
|
||||
var record otellog.Record
|
||||
record.SetTimestamp(time.Now().UTC())
|
||||
record.SetSeverity(otelLogSeverity(level))
|
||||
record.SetBody(otellog.StringValue(message))
|
||||
|
||||
// See https://github.com/rs/zerolog/issues/493.
|
||||
// This is a workaround to get the log fields from the event.
|
||||
// At the moment there's no way to get the log fields from the event, so we use reflection to get the buffer and parse it.
|
||||
logData := make(map[string]any)
|
||||
eventBuffer := fmt.Sprintf("%s}", reflect.ValueOf(e).Elem().FieldByName("buf"))
|
||||
if err := json.Unmarshal([]byte(eventBuffer), &logData); err != nil {
|
||||
record.AddAttributes(otellog.String("parsing_error", fmt.Sprintf("parsing log fields: %s", err)))
|
||||
h.logger.Emit(e.GetCtx(), record)
|
||||
return
|
||||
}
|
||||
|
||||
recordAttributes := make([]otellog.KeyValue, 0, len(logData))
|
||||
for k, v := range logData {
|
||||
if k == "level" {
|
||||
continue
|
||||
}
|
||||
if k == "time" {
|
||||
eventTimestamp, ok := v.(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
t, err := time.Parse(time.RFC3339, eventTimestamp)
|
||||
if err == nil {
|
||||
record.SetTimestamp(t)
|
||||
continue
|
||||
}
|
||||
}
|
||||
var attributeValue otellog.Value
|
||||
switch v := v.(type) {
|
||||
case string:
|
||||
attributeValue = otellog.StringValue(v)
|
||||
case int:
|
||||
attributeValue = otellog.IntValue(v)
|
||||
case int64:
|
||||
attributeValue = otellog.Int64Value(v)
|
||||
case float64:
|
||||
attributeValue = otellog.Float64Value(v)
|
||||
case bool:
|
||||
attributeValue = otellog.BoolValue(v)
|
||||
case []byte:
|
||||
attributeValue = otellog.BytesValue(v)
|
||||
default:
|
||||
attributeValue = otellog.StringValue(fmt.Sprintf("%v", v))
|
||||
}
|
||||
recordAttributes = append(recordAttributes, otellog.KeyValue{
|
||||
Key: k,
|
||||
Value: attributeValue,
|
||||
})
|
||||
}
|
||||
record.AddAttributes(recordAttributes...)
|
||||
|
||||
h.logger.Emit(e.GetCtx(), record)
|
||||
}
|
||||
|
||||
func otelLogSeverity(level zerolog.Level) otellog.Severity {
|
||||
switch level {
|
||||
case zerolog.TraceLevel:
|
||||
return otellog.SeverityTrace
|
||||
case zerolog.DebugLevel:
|
||||
return otellog.SeverityDebug
|
||||
case zerolog.InfoLevel:
|
||||
return otellog.SeverityInfo
|
||||
case zerolog.WarnLevel:
|
||||
return otellog.SeverityWarn
|
||||
case zerolog.ErrorLevel:
|
||||
return otellog.SeverityError
|
||||
case zerolog.FatalLevel:
|
||||
return otellog.SeverityFatal
|
||||
case zerolog.PanicLevel:
|
||||
return otellog.SeverityFatal4
|
||||
default:
|
||||
return otellog.SeverityUndefined
|
||||
}
|
||||
}
|
197
pkg/logs/otel_test.go
Normal file
197
pkg/logs/otel_test.go
Normal file
@ -0,0 +1,197 @@
|
||||
package logs
|
||||
|
||||
import (
|
||||
"compress/gzip"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/traefik/traefik/v3/pkg/types"
|
||||
"go.opentelemetry.io/collector/pdata/plog/plogotlp"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
func TestLog(t *testing.T) {
|
||||
tests := []struct {
|
||||
desc string
|
||||
level zerolog.Level
|
||||
assertFn func(*testing.T, string)
|
||||
noLog bool
|
||||
}{
|
||||
{
|
||||
desc: "no level log",
|
||||
level: zerolog.NoLevel,
|
||||
assertFn: func(t *testing.T, log string) {
|
||||
t.Helper()
|
||||
// SeverityUndefined Severity = 0 // UNDEFINED
|
||||
assert.NotContains(t, log, `"severityNumber"`)
|
||||
assert.Regexp(t, `{"key":"resource","value":{"stringValue":"attribute"}}`, log)
|
||||
assert.Regexp(t, `{"key":"service.name","value":{"stringValue":"test"}}`, log)
|
||||
assert.Regexp(t, `"body":{"stringValue":"test"}`, log)
|
||||
assert.Regexp(t, `{"key":"foo","value":{"stringValue":"bar"}}`, log)
|
||||
assert.Regexp(t, `"traceId":"01020304050607080000000000000000","spanId":"0102030405060708"`, log)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "trace log",
|
||||
level: zerolog.TraceLevel,
|
||||
assertFn: func(t *testing.T, log string) {
|
||||
t.Helper()
|
||||
// SeverityTrace1 Severity = 1 // TRACE
|
||||
assert.Contains(t, log, `"severityNumber":1`)
|
||||
assert.Regexp(t, `{"key":"resource","value":{"stringValue":"attribute"}}`, log)
|
||||
assert.Regexp(t, `{"key":"service.name","value":{"stringValue":"test"}}`, log)
|
||||
assert.Regexp(t, `"body":{"stringValue":"test"}`, log)
|
||||
assert.Regexp(t, `{"key":"foo","value":{"stringValue":"bar"}}`, log)
|
||||
assert.Regexp(t, `"traceId":"01020304050607080000000000000000","spanId":"0102030405060708"`, log)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "debug log",
|
||||
level: zerolog.DebugLevel,
|
||||
assertFn: func(t *testing.T, log string) {
|
||||
t.Helper()
|
||||
// SeverityDebug1 Severity = 5 // DEBUG
|
||||
assert.Contains(t, log, `"severityNumber":5`)
|
||||
assert.Regexp(t, `{"key":"resource","value":{"stringValue":"attribute"}}`, log)
|
||||
assert.Regexp(t, `{"key":"service.name","value":{"stringValue":"test"}}`, log)
|
||||
assert.Regexp(t, `"body":{"stringValue":"test"}`, log)
|
||||
assert.Regexp(t, `{"key":"foo","value":{"stringValue":"bar"}}`, log)
|
||||
assert.Regexp(t, `"traceId":"01020304050607080000000000000000","spanId":"0102030405060708"`, log)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "info log",
|
||||
level: zerolog.InfoLevel,
|
||||
assertFn: func(t *testing.T, log string) {
|
||||
t.Helper()
|
||||
// SeverityInfo1 Severity = 9 // INFO
|
||||
assert.Contains(t, log, `"severityNumber":9`)
|
||||
assert.Regexp(t, `{"key":"resource","value":{"stringValue":"attribute"}}`, log)
|
||||
assert.Regexp(t, `{"key":"service.name","value":{"stringValue":"test"}}`, log)
|
||||
assert.Regexp(t, `"body":{"stringValue":"test"}`, log)
|
||||
assert.Regexp(t, `{"key":"foo","value":{"stringValue":"bar"}}`, log)
|
||||
assert.Regexp(t, `"traceId":"01020304050607080000000000000000","spanId":"0102030405060708"`, log)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "warn log",
|
||||
level: zerolog.WarnLevel,
|
||||
assertFn: func(t *testing.T, log string) {
|
||||
t.Helper()
|
||||
// SeverityWarn1 Severity = 13 // WARN
|
||||
assert.Contains(t, log, `"severityNumber":13`)
|
||||
assert.Regexp(t, `{"key":"resource","value":{"stringValue":"attribute"}}`, log)
|
||||
assert.Regexp(t, `{"key":"service.name","value":{"stringValue":"test"}}`, log)
|
||||
assert.Regexp(t, `"body":{"stringValue":"test"}`, log)
|
||||
assert.Regexp(t, `{"key":"foo","value":{"stringValue":"bar"}}`, log)
|
||||
assert.Regexp(t, `"traceId":"01020304050607080000000000000000","spanId":"0102030405060708"`, log)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "error log",
|
||||
level: zerolog.ErrorLevel,
|
||||
assertFn: func(t *testing.T, log string) {
|
||||
t.Helper()
|
||||
// SeverityError1 Severity = 17 // ERROR
|
||||
assert.Contains(t, log, `"severityNumber":17`)
|
||||
assert.Regexp(t, `{"key":"resource","value":{"stringValue":"attribute"}}`, log)
|
||||
assert.Regexp(t, `{"key":"service.name","value":{"stringValue":"test"}}`, log)
|
||||
assert.Regexp(t, `"body":{"stringValue":"test"}`, log)
|
||||
assert.Regexp(t, `{"key":"foo","value":{"stringValue":"bar"}}`, log)
|
||||
assert.Regexp(t, `"traceId":"01020304050607080000000000000000","spanId":"0102030405060708"`, log)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "fatal log",
|
||||
level: zerolog.FatalLevel,
|
||||
assertFn: func(t *testing.T, log string) {
|
||||
t.Helper()
|
||||
// SeverityFatal Severity = 21 // FATAL
|
||||
assert.Contains(t, log, `"severityNumber":21`)
|
||||
assert.Regexp(t, `{"key":"resource","value":{"stringValue":"attribute"}}`, log)
|
||||
assert.Regexp(t, `{"key":"service.name","value":{"stringValue":"test"}}`, log)
|
||||
assert.Regexp(t, `"body":{"stringValue":"test"}`, log)
|
||||
assert.Regexp(t, `{"key":"foo","value":{"stringValue":"bar"}}`, log)
|
||||
assert.Regexp(t, `"traceId":"01020304050607080000000000000000","spanId":"0102030405060708"`, log)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "panic log",
|
||||
level: zerolog.PanicLevel,
|
||||
assertFn: func(t *testing.T, log string) {
|
||||
t.Helper()
|
||||
// SeverityFatal4 Severity = 24 // FATAL
|
||||
assert.Contains(t, log, `"severityNumber":24`)
|
||||
assert.Regexp(t, `{"key":"resource","value":{"stringValue":"attribute"}}`, log)
|
||||
assert.Regexp(t, `{"key":"service.name","value":{"stringValue":"test"}}`, log)
|
||||
assert.Regexp(t, `"body":{"stringValue":"test"}`, log)
|
||||
assert.Regexp(t, `{"key":"foo","value":{"stringValue":"bar"}}`, log)
|
||||
assert.Regexp(t, `"traceId":"01020304050607080000000000000000","spanId":"0102030405060708"`, log)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
logCh := make(chan string)
|
||||
collector := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
gzr, err := gzip.NewReader(r.Body)
|
||||
require.NoError(t, err)
|
||||
|
||||
body, err := io.ReadAll(gzr)
|
||||
require.NoError(t, err)
|
||||
|
||||
req := plogotlp.NewExportRequest()
|
||||
err = req.UnmarshalProto(body)
|
||||
require.NoError(t, err)
|
||||
|
||||
marshalledReq, err := json.Marshal(req)
|
||||
require.NoError(t, err)
|
||||
|
||||
logCh <- string(marshalledReq)
|
||||
}))
|
||||
t.Cleanup(collector.Close)
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
config := &types.OTelLog{
|
||||
ServiceName: "test",
|
||||
ResourceAttributes: map[string]string{"resource": "attribute"},
|
||||
HTTP: &types.OTelHTTP{
|
||||
Endpoint: collector.URL,
|
||||
},
|
||||
}
|
||||
|
||||
out := zerolog.MultiLevelWriter(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339})
|
||||
logger := zerolog.New(out).With().Caller().Logger()
|
||||
|
||||
logger, err := SetupOTelLogger(logger, config)
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := trace.ContextWithSpanContext(context.Background(), trace.NewSpanContext(trace.SpanContextConfig{
|
||||
TraceID: trace.TraceID{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8},
|
||||
SpanID: trace.SpanID{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8},
|
||||
}))
|
||||
logger = logger.With().Ctx(ctx).Logger()
|
||||
|
||||
logger.WithLevel(test.level).Str("foo", "bar").Msg("test")
|
||||
|
||||
select {
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Error("Log not exported")
|
||||
|
||||
case log := <-logCh:
|
||||
if test.assertFn != nil {
|
||||
test.assertFn(t, log)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -237,7 +237,7 @@ func newOpenTelemetryMeterProvider(ctx context.Context, config *types.OTLP) (*sd
|
||||
return meterProvider, nil
|
||||
}
|
||||
|
||||
func newHTTPExporter(ctx context.Context, config *types.OtelHTTP) (sdkmetric.Exporter, error) {
|
||||
func newHTTPExporter(ctx context.Context, config *types.OTelHTTP) (sdkmetric.Exporter, error) {
|
||||
endpoint, err := url.Parse(config.Endpoint)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid collector endpoint %q: %w", config.Endpoint, err)
|
||||
@ -269,7 +269,7 @@ func newHTTPExporter(ctx context.Context, config *types.OtelHTTP) (sdkmetric.Exp
|
||||
return otlpmetrichttp.New(ctx, opts...)
|
||||
}
|
||||
|
||||
func newGRPCExporter(ctx context.Context, config *types.OtelGRPC) (sdkmetric.Exporter, error) {
|
||||
func newGRPCExporter(ctx context.Context, config *types.OTelGRPC) (sdkmetric.Exporter, error) {
|
||||
host, port, err := net.SplitHostPort(config.Endpoint)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid collector endpoint %q: %w", config.Endpoint, err)
|
@ -327,7 +327,7 @@ func TestOpenTelemetry(t *testing.T) {
|
||||
var cfg types.OTLP
|
||||
(&cfg).SetDefaults()
|
||||
cfg.AddRoutersLabels = true
|
||||
cfg.HTTP = &types.OtelHTTP{
|
||||
cfg.HTTP = &types.OTelHTTP{
|
||||
Endpoint: ts.URL,
|
||||
}
|
||||
cfg.PushInterval = ptypes.Duration(10 * time.Millisecond)
|
@ -23,6 +23,7 @@ import (
|
||||
"github.com/traefik/traefik/v3/pkg/middlewares/capture"
|
||||
traefiktls "github.com/traefik/traefik/v3/pkg/tls"
|
||||
"github.com/traefik/traefik/v3/pkg/types"
|
||||
"go.opentelemetry.io/contrib/bridges/otellogrus"
|
||||
)
|
||||
|
||||
type key string
|
||||
@ -52,6 +53,7 @@ func (n noopCloser) Close() error {
|
||||
}
|
||||
|
||||
type handlerParams struct {
|
||||
ctx context.Context
|
||||
logDataTable *LogData
|
||||
}
|
||||
|
||||
@ -106,6 +108,16 @@ func NewHandler(config *types.AccessLog) (*Handler, error) {
|
||||
Level: logrus.InfoLevel,
|
||||
}
|
||||
|
||||
if config.OTLP != nil {
|
||||
otelLoggerProvider, err := config.OTLP.NewLoggerProvider()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("setting up OpenTelemetry logger provider: %w", err)
|
||||
}
|
||||
|
||||
logger.Hooks.Add(otellogrus.NewHook("traefik", otellogrus.WithLoggerProvider(otelLoggerProvider)))
|
||||
logger.Out = io.Discard
|
||||
}
|
||||
|
||||
// Transform header names to a canonical form, to be used as is without further transformations,
|
||||
// and transform field names to lower case, to enable case-insensitive lookup.
|
||||
if config.Fields != nil {
|
||||
@ -150,7 +162,7 @@ func NewHandler(config *types.AccessLog) (*Handler, error) {
|
||||
go func() {
|
||||
defer logHandler.wg.Done()
|
||||
for handlerParams := range logHandler.logHandlerChan {
|
||||
logHandler.logTheRoundTrip(handlerParams.logDataTable)
|
||||
logHandler.logTheRoundTrip(handlerParams.ctx, handlerParams.logDataTable)
|
||||
}
|
||||
}()
|
||||
}
|
||||
@ -256,12 +268,13 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request, next http
|
||||
|
||||
if h.config.BufferingSize > 0 {
|
||||
h.logHandlerChan <- handlerParams{
|
||||
ctx: req.Context(),
|
||||
logDataTable: logDataTable,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
h.logTheRoundTrip(logDataTable)
|
||||
h.logTheRoundTrip(req.Context(), logDataTable)
|
||||
}()
|
||||
|
||||
next.ServeHTTP(rw, reqWithDataTable)
|
||||
@ -313,7 +326,7 @@ func usernameIfPresent(theURL *url.URL) string {
|
||||
}
|
||||
|
||||
// Logging handler to log frontend name, backend name, and elapsed time.
|
||||
func (h *Handler) logTheRoundTrip(logDataTable *LogData) {
|
||||
func (h *Handler) logTheRoundTrip(ctx context.Context, logDataTable *LogData) {
|
||||
core := logDataTable.Core
|
||||
|
||||
retryAttempts, ok := core[RetryAttempts].(int)
|
||||
@ -359,7 +372,7 @@ func (h *Handler) logTheRoundTrip(logDataTable *LogData) {
|
||||
|
||||
h.mu.Lock()
|
||||
defer h.mu.Unlock()
|
||||
h.logger.WithFields(fields).Println()
|
||||
h.logger.WithContext(ctx).WithFields(fields).Println()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ package accesslog
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
@ -25,6 +26,8 @@ import (
|
||||
ptypes "github.com/traefik/paerser/types"
|
||||
"github.com/traefik/traefik/v3/pkg/middlewares/capture"
|
||||
"github.com/traefik/traefik/v3/pkg/types"
|
||||
"go.opentelemetry.io/collector/pdata/plog/plogotlp"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
const delta float64 = 1e-10
|
||||
@ -49,6 +52,75 @@ var (
|
||||
testStart = time.Now()
|
||||
)
|
||||
|
||||
func TestOTelAccessLog(t *testing.T) {
|
||||
logCh := make(chan string)
|
||||
collector := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
gzr, err := gzip.NewReader(r.Body)
|
||||
require.NoError(t, err)
|
||||
|
||||
body, err := io.ReadAll(gzr)
|
||||
require.NoError(t, err)
|
||||
|
||||
req := plogotlp.NewExportRequest()
|
||||
err = req.UnmarshalProto(body)
|
||||
require.NoError(t, err)
|
||||
|
||||
marshalledReq, err := json.Marshal(req)
|
||||
require.NoError(t, err)
|
||||
|
||||
logCh <- string(marshalledReq)
|
||||
}))
|
||||
t.Cleanup(collector.Close)
|
||||
|
||||
config := &types.AccessLog{
|
||||
OTLP: &types.OTelLog{
|
||||
ServiceName: "test",
|
||||
ResourceAttributes: map[string]string{"resource": "attribute"},
|
||||
HTTP: &types.OTelHTTP{
|
||||
Endpoint: collector.URL,
|
||||
},
|
||||
},
|
||||
}
|
||||
logHandler, err := NewHandler(config)
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
err := logHandler.Close()
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
req := &http.Request{
|
||||
Header: map[string][]string{},
|
||||
URL: &url.URL{
|
||||
Path: testPath,
|
||||
},
|
||||
}
|
||||
ctx := trace.ContextWithSpanContext(context.Background(), trace.NewSpanContext(trace.SpanContextConfig{
|
||||
TraceID: trace.TraceID{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8},
|
||||
SpanID: trace.SpanID{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8},
|
||||
}))
|
||||
req = req.WithContext(ctx)
|
||||
|
||||
chain := alice.New()
|
||||
chain = chain.Append(capture.Wrap)
|
||||
chain = chain.Append(WrapHandler(logHandler))
|
||||
handler, err := chain.Then(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
require.NoError(t, err)
|
||||
handler.ServeHTTP(httptest.NewRecorder(), req)
|
||||
|
||||
select {
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Error("AccessLog not exported")
|
||||
|
||||
case log := <-logCh:
|
||||
assert.Regexp(t, `{"key":"resource","value":{"stringValue":"attribute"}}`, log)
|
||||
assert.Regexp(t, `{"key":"service.name","value":{"stringValue":"test"}}`, log)
|
||||
assert.Regexp(t, `{"key":"DownstreamStatus","value":{"intValue":"200"}}`, log)
|
||||
assert.Regexp(t, `"traceId":"01020304050607080000000000000000","spanId":"0102030405060708"`, log)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogRotation(t *testing.T) {
|
||||
fileName := filepath.Join(t.TempDir(), "traefik.log")
|
||||
rotatedFileName := fileName + ".rotated"
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/containous/alice"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/traefik/traefik/v3/pkg/metrics"
|
||||
"github.com/traefik/traefik/v3/pkg/middlewares"
|
||||
"github.com/traefik/traefik/v3/pkg/middlewares/accesslog"
|
||||
@ -64,7 +65,11 @@ func (e *entryPointTracing) ServeHTTP(rw http.ResponseWriter, req *http.Request)
|
||||
start := time.Now()
|
||||
tracingCtx, span := e.tracer.Start(tracingCtx, "EntryPoint", trace.WithSpanKind(trace.SpanKindServer), trace.WithTimestamp(start))
|
||||
|
||||
req = req.WithContext(tracingCtx)
|
||||
// Associate the request context with the logger.
|
||||
logger := log.Ctx(tracingCtx).With().Ctx(tracingCtx).Logger()
|
||||
loggerCtx := logger.WithContext(tracingCtx)
|
||||
|
||||
req = req.WithContext(loggerCtx)
|
||||
|
||||
span.SetAttributes(attribute.String("entry_point", e.entryPoint))
|
||||
|
||||
|
@ -30,7 +30,6 @@ import (
|
||||
"github.com/traefik/traefik/v3/pkg/provider/kv/zk"
|
||||
"github.com/traefik/traefik/v3/pkg/provider/rest"
|
||||
traefiktls "github.com/traefik/traefik/v3/pkg/tls"
|
||||
"github.com/traefik/traefik/v3/pkg/tracing/opentelemetry"
|
||||
"github.com/traefik/traefik/v3/pkg/types"
|
||||
)
|
||||
|
||||
@ -831,6 +830,25 @@ func TestDo_staticConfiguration(t *testing.T) {
|
||||
MaxAge: 3,
|
||||
MaxBackups: 4,
|
||||
Compress: true,
|
||||
OTLP: &types.OTelLog{
|
||||
ServiceName: "foobar",
|
||||
ResourceAttributes: map[string]string{
|
||||
"foobar": "foobar",
|
||||
},
|
||||
GRPC: &types.OTelGRPC{
|
||||
Endpoint: "foobar",
|
||||
Insecure: true,
|
||||
Headers: map[string]string{
|
||||
"foobar": "foobar",
|
||||
},
|
||||
},
|
||||
HTTP: &types.OTelHTTP{
|
||||
Endpoint: "foobar",
|
||||
Headers: map[string]string{
|
||||
"foobar": "foobar",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
config.AccessLog = &types.AccessLog{
|
||||
@ -854,18 +872,46 @@ func TestDo_staticConfiguration(t *testing.T) {
|
||||
},
|
||||
},
|
||||
BufferingSize: 42,
|
||||
OTLP: &types.OTelLog{
|
||||
ServiceName: "foobar",
|
||||
ResourceAttributes: map[string]string{
|
||||
"foobar": "foobar",
|
||||
},
|
||||
GRPC: &types.OTelGRPC{
|
||||
Endpoint: "foobar",
|
||||
Insecure: true,
|
||||
Headers: map[string]string{
|
||||
"foobar": "foobar",
|
||||
},
|
||||
},
|
||||
HTTP: &types.OTelHTTP{
|
||||
Endpoint: "foobar",
|
||||
Headers: map[string]string{
|
||||
"foobar": "foobar",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
config.Tracing = &static.Tracing{
|
||||
ServiceName: "myServiceName",
|
||||
ResourceAttributes: map[string]string{
|
||||
"foobar": "foobar",
|
||||
},
|
||||
GlobalAttributes: map[string]string{
|
||||
"foobar": "foobar",
|
||||
},
|
||||
SampleRate: 42,
|
||||
OTLP: &opentelemetry.Config{
|
||||
HTTP: &types.OtelHTTP{
|
||||
OTLP: &types.OTelTracing{
|
||||
HTTP: &types.OTelHTTP{
|
||||
Endpoint: "foobar",
|
||||
TLS: nil,
|
||||
Headers: map[string]string{
|
||||
"foobar": "foobar",
|
||||
},
|
||||
},
|
||||
GRPC: &types.OTelGRPC{
|
||||
Endpoint: "foobar",
|
||||
Insecure: true,
|
||||
Headers: map[string]string{
|
||||
"foobar": "foobar",
|
||||
},
|
||||
|
@ -315,7 +315,17 @@
|
||||
"maxSize": 5,
|
||||
"maxAge": 3,
|
||||
"maxBackups": 4,
|
||||
"compress": true
|
||||
"compress": true,
|
||||
"otlp": {
|
||||
"serviceName": "foobar",
|
||||
"grpc": {
|
||||
"endpoint": "xxxx",
|
||||
"insecure": true
|
||||
},
|
||||
"http": {
|
||||
"endpoint": "xxxx"
|
||||
}
|
||||
}
|
||||
},
|
||||
"accessLog": {
|
||||
"filePath": "xxxx",
|
||||
@ -340,18 +350,35 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"bufferingSize": 42
|
||||
"bufferingSize": 42,
|
||||
"otlp": {
|
||||
"serviceName": "foobar",
|
||||
"grpc": {
|
||||
"endpoint": "xxxx",
|
||||
"insecure": true
|
||||
},
|
||||
"http": {
|
||||
"endpoint": "xxxx"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tracing": {
|
||||
"serviceName": "myServiceName",
|
||||
"globalAttributes": {
|
||||
"resourceAttributes": {
|
||||
"foobar": "foobar"
|
||||
},
|
||||
"sampleRate": 42,
|
||||
"otlp": {
|
||||
"grpc": {
|
||||
"endpoint": "xxxx",
|
||||
"insecure": true
|
||||
},
|
||||
"http": {
|
||||
"endpoint": "xxxx"
|
||||
}
|
||||
},
|
||||
"globalAttributes": {
|
||||
"foobar": "foobar"
|
||||
}
|
||||
},
|
||||
"hostResolver": {
|
||||
@ -370,11 +397,11 @@
|
||||
"certificatesDuration": 42,
|
||||
"dnsChallenge": {
|
||||
"provider": "DNSProvider",
|
||||
"delayBeforeCheck": "42ns",
|
||||
"resolvers": [
|
||||
"xxxx",
|
||||
"xxxx"
|
||||
],
|
||||
"delayBeforeCheck": "42ns",
|
||||
"disablePropagationCheck": true
|
||||
},
|
||||
"httpChallenge": {
|
||||
|
@ -54,6 +54,12 @@ func (o *ObservabilityMgr) BuildEPChain(ctx context.Context, entryPointName stri
|
||||
}
|
||||
}
|
||||
|
||||
// As the Entry point observability middleware ensures that the tracing is added to the request and logger context,
|
||||
// it needs to be added before the access log middleware to ensure that the trace ID is logged.
|
||||
if (o.tracer != nil && o.ShouldAddTracing(resourceName)) || (o.metricsRegistry != nil && o.metricsRegistry.IsEpEnabled() && o.ShouldAddMetrics(resourceName)) {
|
||||
chain = chain.Append(observability.WrapEntryPointHandler(ctx, o.tracer, o.semConvMetricRegistry, entryPointName))
|
||||
}
|
||||
|
||||
if o.accessLoggerMiddleware != nil && o.ShouldAddAccessLogs(resourceName) {
|
||||
chain = chain.Append(accesslog.WrapHandler(o.accessLoggerMiddleware))
|
||||
chain = chain.Append(func(next http.Handler) (http.Handler, error) {
|
||||
@ -61,10 +67,6 @@ func (o *ObservabilityMgr) BuildEPChain(ctx context.Context, entryPointName stri
|
||||
})
|
||||
}
|
||||
|
||||
if (o.tracer != nil && o.ShouldAddTracing(resourceName)) || (o.metricsRegistry != nil && o.metricsRegistry.IsEpEnabled() && o.ShouldAddMetrics(resourceName)) {
|
||||
chain = chain.Append(observability.WrapEntryPointHandler(ctx, o.tracer, o.semConvMetricRegistry, entryPointName))
|
||||
}
|
||||
|
||||
if o.metricsRegistry != nil && o.metricsRegistry.IsEpEnabled() && o.ShouldAddMetrics(resourceName) {
|
||||
metricsHandler := metricsMiddle.WrapEntryPointHandler(ctx, o.metricsRegistry, entryPointName)
|
||||
|
||||
|
@ -1,324 +0,0 @@
|
||||
package opentelemetry_test
|
||||
|
||||
import (
|
||||
"compress/gzip"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/containous/alice"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/traefik/traefik/v3/pkg/config/static"
|
||||
"github.com/traefik/traefik/v3/pkg/middlewares/observability"
|
||||
"github.com/traefik/traefik/v3/pkg/tracing"
|
||||
"github.com/traefik/traefik/v3/pkg/tracing/opentelemetry"
|
||||
"github.com/traefik/traefik/v3/pkg/types"
|
||||
"go.opentelemetry.io/collector/pdata/ptrace/ptraceotlp"
|
||||
)
|
||||
|
||||
func TestTracing(t *testing.T) {
|
||||
tests := []struct {
|
||||
desc string
|
||||
propagators string
|
||||
headers map[string]string
|
||||
wantServiceHeadersFn func(t *testing.T, headers http.Header)
|
||||
assertFn func(*testing.T, string)
|
||||
}{
|
||||
{
|
||||
desc: "service name and version",
|
||||
assertFn: func(t *testing.T, trace string) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `({"key":"service.name","value":{"stringValue":"traefik"}})`, trace)
|
||||
assert.Regexp(t, `({"key":"service.version","value":{"stringValue":"dev"}})`, trace)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "TraceContext propagation",
|
||||
propagators: "tracecontext",
|
||||
headers: map[string]string{
|
||||
"traceparent": "00-00000000000000000000000000000001-0000000000000001-01",
|
||||
"tracestate": "foo=bar",
|
||||
},
|
||||
wantServiceHeadersFn: func(t *testing.T, headers http.Header) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `(00-00000000000000000000000000000001-\w{16}-01)`, headers["Traceparent"][0])
|
||||
assert.Equal(t, []string{"foo=bar"}, headers["Tracestate"])
|
||||
},
|
||||
assertFn: func(t *testing.T, trace string) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `("traceId":"00000000000000000000000000000001")`, trace)
|
||||
assert.Regexp(t, `("parentSpanId":"0000000000000001")`, trace)
|
||||
assert.Regexp(t, `("traceState":"foo=bar")`, trace)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "root span TraceContext propagation",
|
||||
propagators: "tracecontext",
|
||||
wantServiceHeadersFn: func(t *testing.T, headers http.Header) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `(00-\w{32}-\w{16}-01)`, headers["Traceparent"][0])
|
||||
},
|
||||
assertFn: func(t *testing.T, trace string) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `("traceId":"\w{32}")`, trace)
|
||||
assert.Regexp(t, `("parentSpanId":"\w{16}")`, trace)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "B3 propagation",
|
||||
propagators: "b3",
|
||||
headers: map[string]string{
|
||||
"b3": "00000000000000000000000000000001-0000000000000002-1-0000000000000001",
|
||||
},
|
||||
wantServiceHeadersFn: func(t *testing.T, headers http.Header) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `(00000000000000000000000000000001-\w{16}-1)`, headers["B3"][0])
|
||||
},
|
||||
assertFn: func(t *testing.T, trace string) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `("traceId":"00000000000000000000000000000001")`, trace)
|
||||
assert.Regexp(t, `("parentSpanId":"0000000000000002")`, trace)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "root span B3 propagation",
|
||||
propagators: "b3",
|
||||
wantServiceHeadersFn: func(t *testing.T, headers http.Header) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `(\w{32}-\w{16}-1)`, headers["B3"][0])
|
||||
},
|
||||
assertFn: func(t *testing.T, trace string) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `("traceId":"\w{32}")`, trace)
|
||||
assert.Regexp(t, `("parentSpanId":"\w{16}")`, trace)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "B3 propagation Multiple Headers",
|
||||
propagators: "b3multi",
|
||||
headers: map[string]string{
|
||||
"x-b3-traceid": "00000000000000000000000000000001",
|
||||
"x-b3-parentspanid": "0000000000000001",
|
||||
"x-b3-spanid": "0000000000000002",
|
||||
"x-b3-sampled": "1",
|
||||
},
|
||||
wantServiceHeadersFn: func(t *testing.T, headers http.Header) {
|
||||
t.Helper()
|
||||
|
||||
assert.Equal(t, "00000000000000000000000000000001", headers["X-B3-Traceid"][0])
|
||||
assert.Equal(t, "0000000000000001", headers["X-B3-Parentspanid"][0])
|
||||
assert.Equal(t, "1", headers["X-B3-Sampled"][0])
|
||||
assert.Len(t, headers["X-B3-Spanid"][0], 16)
|
||||
},
|
||||
assertFn: func(t *testing.T, trace string) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `("traceId":"00000000000000000000000000000001")`, trace)
|
||||
assert.Regexp(t, `("parentSpanId":"0000000000000002")`, trace)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "root span B3 propagation Multiple Headers",
|
||||
propagators: "b3multi",
|
||||
wantServiceHeadersFn: func(t *testing.T, headers http.Header) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `(\w{32})`, headers["X-B3-Traceid"][0])
|
||||
assert.Equal(t, "1", headers["X-B3-Sampled"][0])
|
||||
assert.Regexp(t, `(\w{16})`, headers["X-B3-Spanid"][0])
|
||||
},
|
||||
assertFn: func(t *testing.T, trace string) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `("traceId":"\w{32}")`, trace)
|
||||
assert.Regexp(t, `("parentSpanId":"")`, trace)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Baggage propagation",
|
||||
propagators: "baggage",
|
||||
headers: map[string]string{
|
||||
"baggage": "userId=id",
|
||||
},
|
||||
wantServiceHeadersFn: func(t *testing.T, headers http.Header) {
|
||||
t.Helper()
|
||||
|
||||
assert.Equal(t, []string{"userId=id"}, headers["Baggage"])
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Jaeger propagation",
|
||||
propagators: "jaeger",
|
||||
headers: map[string]string{
|
||||
"uber-trace-id": "00000000000000000000000000000001:0000000000000002:0000000000000001:1",
|
||||
},
|
||||
wantServiceHeadersFn: func(t *testing.T, headers http.Header) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `(00000000000000000000000000000001:\w{16}:0:1)`, headers["Uber-Trace-Id"][0])
|
||||
},
|
||||
assertFn: func(t *testing.T, trace string) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `("traceId":"00000000000000000000000000000001")`, trace)
|
||||
assert.Regexp(t, `("parentSpanId":"\w{16}")`, trace)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "root span Jaeger propagation",
|
||||
propagators: "jaeger",
|
||||
wantServiceHeadersFn: func(t *testing.T, headers http.Header) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `(\w{32}:\w{16}:0:1)`, headers["Uber-Trace-Id"][0])
|
||||
},
|
||||
assertFn: func(t *testing.T, trace string) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `("traceId":"\w{32}")`, trace)
|
||||
assert.Regexp(t, `("parentSpanId":"\w{16}")`, trace)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "XRay propagation",
|
||||
propagators: "xray",
|
||||
headers: map[string]string{
|
||||
"X-Amzn-Trace-Id": "Root=1-5759e988-bd862e3fe1be46a994272793;Parent=53995c3f42cd8ad8;Sampled=1",
|
||||
},
|
||||
wantServiceHeadersFn: func(t *testing.T, headers http.Header) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `(Root=1-5759e988-bd862e3fe1be46a994272793;Parent=\w{16};Sampled=1)`, headers["X-Amzn-Trace-Id"][0])
|
||||
},
|
||||
assertFn: func(t *testing.T, trace string) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `("traceId":"5759e988bd862e3fe1be46a994272793")`, trace)
|
||||
assert.Regexp(t, `("parentSpanId":"\w{16}")`, trace)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "root span XRay propagation",
|
||||
propagators: "xray",
|
||||
wantServiceHeadersFn: func(t *testing.T, headers http.Header) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `(Root=1-\w{8}-\w{24};Parent=\w{16};Sampled=1)`, headers["X-Amzn-Trace-Id"][0])
|
||||
},
|
||||
assertFn: func(t *testing.T, trace string) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `("traceId":"\w{32}")`, trace)
|
||||
assert.Regexp(t, `("parentSpanId":"\w{16}")`, trace)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "no propagation",
|
||||
propagators: "none",
|
||||
wantServiceHeadersFn: func(t *testing.T, headers http.Header) {
|
||||
t.Helper()
|
||||
|
||||
assert.Empty(t, headers)
|
||||
},
|
||||
assertFn: func(t *testing.T, trace string) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `("traceId":"\w{32}")`, trace)
|
||||
assert.Regexp(t, `("parentSpanId":"\w{16}")`, trace)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
traceCh := make(chan string)
|
||||
collector := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
gzr, err := gzip.NewReader(r.Body)
|
||||
require.NoError(t, err)
|
||||
|
||||
body, err := io.ReadAll(gzr)
|
||||
require.NoError(t, err)
|
||||
|
||||
req := ptraceotlp.NewExportRequest()
|
||||
err = req.UnmarshalProto(body)
|
||||
require.NoError(t, err)
|
||||
|
||||
marshalledReq, err := json.Marshal(req)
|
||||
require.NoError(t, err)
|
||||
|
||||
traceCh <- string(marshalledReq)
|
||||
}))
|
||||
t.Cleanup(collector.Close)
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Setenv("OTEL_PROPAGATORS", test.propagators)
|
||||
|
||||
service := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
tracer := tracing.TracerFromContext(r.Context())
|
||||
ctx, span := tracer.Start(r.Context(), "service")
|
||||
defer span.End()
|
||||
|
||||
r = r.WithContext(ctx)
|
||||
|
||||
tracing.InjectContextIntoCarrier(r)
|
||||
|
||||
if test.wantServiceHeadersFn != nil {
|
||||
test.wantServiceHeadersFn(t, r.Header)
|
||||
}
|
||||
})
|
||||
|
||||
tracingConfig := &static.Tracing{
|
||||
ServiceName: "traefik",
|
||||
SampleRate: 1.0,
|
||||
OTLP: &opentelemetry.Config{
|
||||
HTTP: &types.OtelHTTP{
|
||||
Endpoint: collector.URL,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
newTracing, closer, err := tracing.NewTracing(tracingConfig)
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
_ = closer.Close()
|
||||
})
|
||||
|
||||
chain := alice.New(observability.WrapEntryPointHandler(context.Background(), newTracing, nil, "test"))
|
||||
epHandler, err := chain.Then(service)
|
||||
require.NoError(t, err)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "http://www.test.com", nil)
|
||||
for k, v := range test.headers {
|
||||
req.Header.Set(k, v)
|
||||
}
|
||||
|
||||
rw := httptest.NewRecorder()
|
||||
|
||||
epHandler.ServeHTTP(rw, req)
|
||||
|
||||
select {
|
||||
case <-time.After(10 * time.Second):
|
||||
t.Error("Trace not exported")
|
||||
|
||||
case trace := <-traceCh:
|
||||
assert.Equal(t, http.StatusOK, rw.Code)
|
||||
if test.assertFn != nil {
|
||||
test.assertFn(t, trace)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -13,7 +13,7 @@ import (
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/traefik/traefik/v3/pkg/config/static"
|
||||
"github.com/traefik/traefik/v3/pkg/tracing/opentelemetry"
|
||||
"github.com/traefik/traefik/v3/pkg/types"
|
||||
"go.opentelemetry.io/contrib/propagators/autoprop"
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
@ -38,7 +38,7 @@ func NewTracing(conf *static.Tracing) (*Tracer, io.Closer, error) {
|
||||
|
||||
if backend == nil {
|
||||
log.Debug().Msg("Could not initialize tracing, using OpenTelemetry by default")
|
||||
defaultBackend := &opentelemetry.Config{}
|
||||
defaultBackend := &types.OTelTracing{}
|
||||
backend = defaultBackend
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,22 @@
|
||||
package tracing
|
||||
|
||||
import (
|
||||
"compress/gzip"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/containous/alice"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/traefik/traefik/v3/pkg/config/static"
|
||||
"github.com/traefik/traefik/v3/pkg/types"
|
||||
"go.opentelemetry.io/collector/pdata/ptrace/ptraceotlp"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
func Test_safeFullURL(t *testing.T) {
|
||||
@ -55,3 +67,315 @@ func Test_safeFullURL(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTracing(t *testing.T) {
|
||||
tests := []struct {
|
||||
desc string
|
||||
propagators string
|
||||
headers map[string]string
|
||||
wantServiceHeadersFn func(t *testing.T, headers http.Header)
|
||||
assertFn func(*testing.T, string)
|
||||
}{
|
||||
{
|
||||
desc: "service name and version",
|
||||
assertFn: func(t *testing.T, trace string) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `({"key":"service.name","value":{"stringValue":"traefik"}})`, trace)
|
||||
assert.Regexp(t, `({"key":"service.version","value":{"stringValue":"dev"}})`, trace)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "TraceContext propagation",
|
||||
propagators: "tracecontext",
|
||||
headers: map[string]string{
|
||||
"traceparent": "00-00000000000000000000000000000001-0000000000000001-01",
|
||||
"tracestate": "foo=bar",
|
||||
},
|
||||
wantServiceHeadersFn: func(t *testing.T, headers http.Header) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `(00-00000000000000000000000000000001-\w{16}-01)`, headers["Traceparent"][0])
|
||||
assert.Equal(t, []string{"foo=bar"}, headers["Tracestate"])
|
||||
},
|
||||
assertFn: func(t *testing.T, trace string) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `("traceId":"00000000000000000000000000000001")`, trace)
|
||||
assert.Regexp(t, `("parentSpanId":"0000000000000001")`, trace)
|
||||
assert.Regexp(t, `("traceState":"foo=bar")`, trace)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "root span TraceContext propagation",
|
||||
propagators: "tracecontext",
|
||||
wantServiceHeadersFn: func(t *testing.T, headers http.Header) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `(00-\w{32}-\w{16}-01)`, headers["Traceparent"][0])
|
||||
},
|
||||
assertFn: func(t *testing.T, trace string) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `("traceId":"\w{32}")`, trace)
|
||||
assert.Regexp(t, `("parentSpanId":"\w{16}")`, trace)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "B3 propagation",
|
||||
propagators: "b3",
|
||||
headers: map[string]string{
|
||||
"b3": "00000000000000000000000000000001-0000000000000002-1-0000000000000001",
|
||||
},
|
||||
wantServiceHeadersFn: func(t *testing.T, headers http.Header) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `(00000000000000000000000000000001-\w{16}-1)`, headers["B3"][0])
|
||||
},
|
||||
assertFn: func(t *testing.T, trace string) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `("traceId":"00000000000000000000000000000001")`, trace)
|
||||
assert.Regexp(t, `("parentSpanId":"0000000000000002")`, trace)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "root span B3 propagation",
|
||||
propagators: "b3",
|
||||
wantServiceHeadersFn: func(t *testing.T, headers http.Header) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `(\w{32}-\w{16}-1)`, headers["B3"][0])
|
||||
},
|
||||
assertFn: func(t *testing.T, trace string) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `("traceId":"\w{32}")`, trace)
|
||||
assert.Regexp(t, `("parentSpanId":"\w{16}")`, trace)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "B3 propagation Multiple Headers",
|
||||
propagators: "b3multi",
|
||||
headers: map[string]string{
|
||||
"x-b3-traceid": "00000000000000000000000000000001",
|
||||
"x-b3-parentspanid": "0000000000000001",
|
||||
"x-b3-spanid": "0000000000000002",
|
||||
"x-b3-sampled": "1",
|
||||
},
|
||||
wantServiceHeadersFn: func(t *testing.T, headers http.Header) {
|
||||
t.Helper()
|
||||
|
||||
assert.Equal(t, "00000000000000000000000000000001", headers["X-B3-Traceid"][0])
|
||||
assert.Equal(t, "0000000000000001", headers["X-B3-Parentspanid"][0])
|
||||
assert.Equal(t, "1", headers["X-B3-Sampled"][0])
|
||||
assert.Len(t, headers["X-B3-Spanid"][0], 16)
|
||||
},
|
||||
assertFn: func(t *testing.T, trace string) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `("traceId":"00000000000000000000000000000001")`, trace)
|
||||
assert.Regexp(t, `("parentSpanId":"0000000000000002")`, trace)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "root span B3 propagation Multiple Headers",
|
||||
propagators: "b3multi",
|
||||
wantServiceHeadersFn: func(t *testing.T, headers http.Header) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `(\w{32})`, headers["X-B3-Traceid"][0])
|
||||
assert.Equal(t, "1", headers["X-B3-Sampled"][0])
|
||||
assert.Regexp(t, `(\w{16})`, headers["X-B3-Spanid"][0])
|
||||
},
|
||||
assertFn: func(t *testing.T, trace string) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `("traceId":"\w{32}")`, trace)
|
||||
assert.Regexp(t, `("parentSpanId":"")`, trace)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Baggage propagation",
|
||||
propagators: "baggage",
|
||||
headers: map[string]string{
|
||||
"baggage": "userId=id",
|
||||
},
|
||||
wantServiceHeadersFn: func(t *testing.T, headers http.Header) {
|
||||
t.Helper()
|
||||
|
||||
assert.Equal(t, []string{"userId=id"}, headers["Baggage"])
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Jaeger propagation",
|
||||
propagators: "jaeger",
|
||||
headers: map[string]string{
|
||||
"uber-trace-id": "00000000000000000000000000000001:0000000000000002:0000000000000001:1",
|
||||
},
|
||||
wantServiceHeadersFn: func(t *testing.T, headers http.Header) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `(00000000000000000000000000000001:\w{16}:0:1)`, headers["Uber-Trace-Id"][0])
|
||||
},
|
||||
assertFn: func(t *testing.T, trace string) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `("traceId":"00000000000000000000000000000001")`, trace)
|
||||
assert.Regexp(t, `("parentSpanId":"\w{16}")`, trace)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "root span Jaeger propagation",
|
||||
propagators: "jaeger",
|
||||
wantServiceHeadersFn: func(t *testing.T, headers http.Header) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `(\w{32}:\w{16}:0:1)`, headers["Uber-Trace-Id"][0])
|
||||
},
|
||||
assertFn: func(t *testing.T, trace string) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `("traceId":"\w{32}")`, trace)
|
||||
assert.Regexp(t, `("parentSpanId":"\w{16}")`, trace)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "XRay propagation",
|
||||
propagators: "xray",
|
||||
headers: map[string]string{
|
||||
"X-Amzn-Trace-Id": "Root=1-5759e988-bd862e3fe1be46a994272793;Parent=53995c3f42cd8ad8;Sampled=1",
|
||||
},
|
||||
wantServiceHeadersFn: func(t *testing.T, headers http.Header) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `(Root=1-5759e988-bd862e3fe1be46a994272793;Parent=\w{16};Sampled=1)`, headers["X-Amzn-Trace-Id"][0])
|
||||
},
|
||||
assertFn: func(t *testing.T, trace string) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `("traceId":"5759e988bd862e3fe1be46a994272793")`, trace)
|
||||
assert.Regexp(t, `("parentSpanId":"\w{16}")`, trace)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "root span XRay propagation",
|
||||
propagators: "xray",
|
||||
wantServiceHeadersFn: func(t *testing.T, headers http.Header) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `(Root=1-\w{8}-\w{24};Parent=\w{16};Sampled=1)`, headers["X-Amzn-Trace-Id"][0])
|
||||
},
|
||||
assertFn: func(t *testing.T, trace string) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `("traceId":"\w{32}")`, trace)
|
||||
assert.Regexp(t, `("parentSpanId":"\w{16}")`, trace)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "no propagation",
|
||||
propagators: "none",
|
||||
wantServiceHeadersFn: func(t *testing.T, headers http.Header) {
|
||||
t.Helper()
|
||||
|
||||
assert.Empty(t, headers)
|
||||
},
|
||||
assertFn: func(t *testing.T, trace string) {
|
||||
t.Helper()
|
||||
|
||||
assert.Regexp(t, `("traceId":"\w{32}")`, trace)
|
||||
assert.Regexp(t, `("parentSpanId":"\w{16}")`, trace)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
traceCh := make(chan string)
|
||||
collector := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
gzr, err := gzip.NewReader(r.Body)
|
||||
require.NoError(t, err)
|
||||
|
||||
body, err := io.ReadAll(gzr)
|
||||
require.NoError(t, err)
|
||||
|
||||
req := ptraceotlp.NewExportRequest()
|
||||
err = req.UnmarshalProto(body)
|
||||
require.NoError(t, err)
|
||||
|
||||
marshalledReq, err := json.Marshal(req)
|
||||
require.NoError(t, err)
|
||||
|
||||
traceCh <- string(marshalledReq)
|
||||
}))
|
||||
t.Cleanup(collector.Close)
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Setenv("OTEL_PROPAGATORS", test.propagators)
|
||||
|
||||
service := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
tracer := TracerFromContext(r.Context())
|
||||
ctx, span := tracer.Start(r.Context(), "service")
|
||||
defer span.End()
|
||||
|
||||
r = r.WithContext(ctx)
|
||||
|
||||
InjectContextIntoCarrier(r)
|
||||
|
||||
if test.wantServiceHeadersFn != nil {
|
||||
test.wantServiceHeadersFn(t, r.Header)
|
||||
}
|
||||
})
|
||||
|
||||
tracingConfig := &static.Tracing{
|
||||
ServiceName: "traefik",
|
||||
SampleRate: 1.0,
|
||||
OTLP: &types.OTelTracing{
|
||||
HTTP: &types.OTelHTTP{
|
||||
Endpoint: collector.URL,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
tracer, closer, err := NewTracing(tracingConfig)
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
_ = closer.Close()
|
||||
})
|
||||
|
||||
chain := alice.New(func(next http.Handler) (http.Handler, error) {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
tracingCtx := ExtractCarrierIntoContext(r.Context(), r.Header)
|
||||
start := time.Now()
|
||||
tracingCtx, span := tracer.Start(tracingCtx, "test", trace.WithSpanKind(trace.SpanKindServer), trace.WithTimestamp(start))
|
||||
end := time.Now()
|
||||
span.End(trace.WithTimestamp(end))
|
||||
next.ServeHTTP(w, r.WithContext(tracingCtx))
|
||||
}), nil
|
||||
})
|
||||
|
||||
epHandler, err := chain.Then(service)
|
||||
require.NoError(t, err)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "http://www.test.com", nil)
|
||||
for k, v := range test.headers {
|
||||
req.Header.Set(k, v)
|
||||
}
|
||||
|
||||
rw := httptest.NewRecorder()
|
||||
|
||||
epHandler.ServeHTTP(rw, req)
|
||||
|
||||
select {
|
||||
case <-time.After(10 * time.Second):
|
||||
t.Error("Trace not exported")
|
||||
|
||||
case trace := <-traceCh:
|
||||
assert.Equal(t, http.StatusOK, rw.Code)
|
||||
if test.assertFn != nil {
|
||||
test.assertFn(t, trace)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,22 @@
|
||||
package types
|
||||
|
||||
import "github.com/traefik/paerser/types"
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
|
||||
"github.com/traefik/paerser/types"
|
||||
"github.com/traefik/traefik/v3/pkg/version"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc"
|
||||
"go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp"
|
||||
otelsdk "go.opentelemetry.io/otel/sdk/log"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.27.0"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/encoding/gzip"
|
||||
)
|
||||
|
||||
const (
|
||||
// AccessLogKeep is the keep string value.
|
||||
@ -14,11 +30,10 @@ const (
|
||||
const (
|
||||
// CommonFormat is the common logging format (CLF).
|
||||
CommonFormat string = "common"
|
||||
|
||||
// JSONFormat is the JSON logging format.
|
||||
JSONFormat string = "json"
|
||||
)
|
||||
|
||||
const OTelTraefikServiceName = "traefik"
|
||||
|
||||
// TraefikLog holds the configuration settings for the traefik logger.
|
||||
type TraefikLog struct {
|
||||
Level string `description:"Log level set to traefik logs." json:"level,omitempty" toml:"level,omitempty" yaml:"level,omitempty" export:"true"`
|
||||
@ -30,6 +45,8 @@ type TraefikLog struct {
|
||||
MaxAge int `description:"Maximum number of days to retain old log files based on the timestamp encoded in their filename." json:"maxAge,omitempty" toml:"maxAge,omitempty" yaml:"maxAge,omitempty" export:"true"`
|
||||
MaxBackups int `description:"Maximum number of old log files to retain." json:"maxBackups,omitempty" toml:"maxBackups,omitempty" yaml:"maxBackups,omitempty" export:"true"`
|
||||
Compress bool `description:"Determines if the rotated log files should be compressed using gzip." json:"compress,omitempty" toml:"compress,omitempty" yaml:"compress,omitempty" export:"true"`
|
||||
|
||||
OTLP *OTelLog `description:"Settings for OpenTelemetry." json:"otlp,omitempty" toml:"otlp,omitempty" yaml:"otlp,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
||||
}
|
||||
|
||||
// SetDefaults sets the default values.
|
||||
@ -46,6 +63,8 @@ type AccessLog struct {
|
||||
Fields *AccessLogFields `description:"AccessLogFields." json:"fields,omitempty" toml:"fields,omitempty" yaml:"fields,omitempty" export:"true"`
|
||||
BufferingSize int64 `description:"Number of access log lines to process in a buffered way." json:"bufferingSize,omitempty" toml:"bufferingSize,omitempty" yaml:"bufferingSize,omitempty" export:"true"`
|
||||
AddInternals bool `description:"Enables access log for internal services (ping, dashboard, etc...)." json:"addInternals,omitempty" toml:"addInternals,omitempty" yaml:"addInternals,omitempty" export:"true"`
|
||||
|
||||
OTLP *OTelLog `description:"Settings for OpenTelemetry." json:"otlp,omitempty" toml:"otlp,omitempty" yaml:"otlp,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
||||
}
|
||||
|
||||
// SetDefaults sets the default values.
|
||||
@ -128,3 +147,123 @@ func checkFieldHeaderValue(value, defaultValue string) string {
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
// OTelLog provides configuration settings for the open-telemetry logger.
|
||||
type OTelLog struct {
|
||||
ServiceName string `description:"Set the name for this service." 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"`
|
||||
GRPC *OTelGRPC `description:"gRPC configuration for the OpenTelemetry collector." json:"grpc,omitempty" toml:"grpc,omitempty" yaml:"grpc,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
||||
HTTP *OTelHTTP `description:"HTTP configuration for the OpenTelemetry collector." json:"http,omitempty" toml:"http,omitempty" yaml:"http,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
||||
}
|
||||
|
||||
// SetDefaults sets the default values.
|
||||
func (o *OTelLog) SetDefaults() {
|
||||
o.ServiceName = OTelTraefikServiceName
|
||||
o.HTTP = &OTelHTTP{}
|
||||
o.HTTP.SetDefaults()
|
||||
}
|
||||
|
||||
// NewLoggerProvider creates a new OpenTelemetry logger provider.
|
||||
func (o *OTelLog) NewLoggerProvider() (*otelsdk.LoggerProvider, error) {
|
||||
var (
|
||||
err error
|
||||
exporter otelsdk.Exporter
|
||||
)
|
||||
if o.GRPC != nil {
|
||||
exporter, err = o.buildGRPCExporter()
|
||||
} else {
|
||||
exporter, err = o.buildHTTPExporter()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("setting up exporter: %w", err)
|
||||
}
|
||||
|
||||
attr := []attribute.KeyValue{
|
||||
semconv.ServiceNameKey.String(o.ServiceName),
|
||||
semconv.ServiceVersionKey.String(version.Version),
|
||||
}
|
||||
|
||||
for k, v := range o.ResourceAttributes {
|
||||
attr = append(attr, attribute.String(k, v))
|
||||
}
|
||||
|
||||
res, err := resource.New(context.Background(),
|
||||
resource.WithAttributes(attr...),
|
||||
resource.WithFromEnv(),
|
||||
resource.WithTelemetrySDK(),
|
||||
resource.WithOSType(),
|
||||
resource.WithProcessCommandArgs(),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("building resource: %w", err)
|
||||
}
|
||||
|
||||
// Register the trace provider to allow the global logger to access it.
|
||||
bp := otelsdk.NewBatchProcessor(exporter)
|
||||
loggerProvider := otelsdk.NewLoggerProvider(
|
||||
otelsdk.WithResource(res),
|
||||
otelsdk.WithProcessor(bp),
|
||||
)
|
||||
|
||||
return loggerProvider, nil
|
||||
}
|
||||
|
||||
func (o *OTelLog) buildHTTPExporter() (*otlploghttp.Exporter, error) {
|
||||
endpoint, err := url.Parse(o.HTTP.Endpoint)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid collector endpoint %q: %w", o.HTTP.Endpoint, err)
|
||||
}
|
||||
|
||||
opts := []otlploghttp.Option{
|
||||
otlploghttp.WithEndpoint(endpoint.Host),
|
||||
otlploghttp.WithHeaders(o.HTTP.Headers),
|
||||
otlploghttp.WithCompression(otlploghttp.GzipCompression),
|
||||
}
|
||||
|
||||
if endpoint.Scheme == "http" {
|
||||
opts = append(opts, otlploghttp.WithInsecure())
|
||||
}
|
||||
|
||||
if endpoint.Path != "" {
|
||||
opts = append(opts, otlploghttp.WithURLPath(endpoint.Path))
|
||||
}
|
||||
|
||||
if o.HTTP.TLS != nil {
|
||||
tlsConfig, err := o.HTTP.TLS.CreateTLSConfig(context.Background())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("creating TLS client config: %w", err)
|
||||
}
|
||||
|
||||
opts = append(opts, otlploghttp.WithTLSClientConfig(tlsConfig))
|
||||
}
|
||||
|
||||
return otlploghttp.New(context.Background(), opts...)
|
||||
}
|
||||
|
||||
func (o *OTelLog) buildGRPCExporter() (*otlploggrpc.Exporter, error) {
|
||||
host, port, err := net.SplitHostPort(o.GRPC.Endpoint)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid collector endpoint %q: %w", o.GRPC.Endpoint, err)
|
||||
}
|
||||
|
||||
opts := []otlploggrpc.Option{
|
||||
otlploggrpc.WithEndpoint(fmt.Sprintf("%s:%s", host, port)),
|
||||
otlploggrpc.WithHeaders(o.GRPC.Headers),
|
||||
otlploggrpc.WithCompressor(gzip.Name),
|
||||
}
|
||||
|
||||
if o.GRPC.Insecure {
|
||||
opts = append(opts, otlploggrpc.WithInsecure())
|
||||
}
|
||||
|
||||
if o.GRPC.TLS != nil {
|
||||
tlsConfig, err := o.GRPC.TLS.CreateTLSConfig(context.Background())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("creating TLS client config: %w", err)
|
||||
}
|
||||
|
||||
opts = append(opts, otlploggrpc.WithTLSCredentials(credentials.NewTLS(tlsConfig)))
|
||||
}
|
||||
|
||||
return otlploggrpc.New(context.Background(), opts...)
|
||||
}
|
||||
|
@ -108,8 +108,8 @@ func (i *InfluxDB2) SetDefaults() {
|
||||
|
||||
// OTLP contains specific configuration used by the OpenTelemetry Metrics exporter.
|
||||
type OTLP struct {
|
||||
GRPC *OtelGRPC `description:"gRPC configuration for the OpenTelemetry collector." json:"grpc,omitempty" toml:"grpc,omitempty" yaml:"grpc,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
||||
HTTP *OtelHTTP `description:"HTTP configuration for the OpenTelemetry collector." json:"http,omitempty" toml:"http,omitempty" yaml:"http,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
||||
GRPC *OTelGRPC `description:"gRPC configuration for the OpenTelemetry collector." json:"grpc,omitempty" toml:"grpc,omitempty" yaml:"grpc,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
||||
HTTP *OTelHTTP `description:"HTTP configuration for the OpenTelemetry collector." json:"http,omitempty" toml:"http,omitempty" yaml:"http,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
||||
|
||||
AddEntryPointsLabels bool `description:"Enable metrics on entry points." json:"addEntryPointsLabels,omitempty" toml:"addEntryPointsLabels,omitempty" yaml:"addEntryPointsLabels,omitempty" export:"true"`
|
||||
AddRoutersLabels bool `description:"Enable metrics on routers." json:"addRoutersLabels,omitempty" toml:"addRoutersLabels,omitempty" yaml:"addRoutersLabels,omitempty" export:"true"`
|
||||
@ -121,14 +121,14 @@ type OTLP struct {
|
||||
|
||||
// SetDefaults sets the default values.
|
||||
func (o *OTLP) SetDefaults() {
|
||||
o.HTTP = &OtelHTTP{}
|
||||
o.HTTP = &OTelHTTP{}
|
||||
o.HTTP.SetDefaults()
|
||||
|
||||
o.AddEntryPointsLabels = true
|
||||
o.AddServicesLabels = true
|
||||
o.ExplicitBoundaries = []float64{.005, .01, .025, .05, .075, .1, .25, .5, .75, 1, 2.5, 5, 7.5, 10}
|
||||
o.PushInterval = types.Duration(10 * time.Second)
|
||||
o.ServiceName = "traefik"
|
||||
o.ServiceName = OTelTraefikServiceName
|
||||
}
|
||||
|
||||
// Statistics provides options for monitoring request and response stats.
|
||||
@ -140,28 +140,3 @@ type Statistics struct {
|
||||
func (s *Statistics) SetDefaults() {
|
||||
s.RecentErrors = 10
|
||||
}
|
||||
|
||||
// OtelGRPC provides configuration settings for the gRPC open-telemetry.
|
||||
type OtelGRPC struct {
|
||||
Endpoint string `description:"Sets the gRPC endpoint (host:port) of the collector." json:"endpoint,omitempty" toml:"endpoint,omitempty" yaml:"endpoint,omitempty"`
|
||||
Insecure bool `description:"Disables client transport security for the exporter." json:"insecure,omitempty" toml:"insecure,omitempty" yaml:"insecure,omitempty" export:"true"`
|
||||
TLS *ClientTLS `description:"Defines client transport security parameters." json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" export:"true"`
|
||||
Headers map[string]string `description:"Headers sent with payload." json:"headers,omitempty" toml:"headers,omitempty" yaml:"headers,omitempty"`
|
||||
}
|
||||
|
||||
// SetDefaults sets the default values.
|
||||
func (c *OtelGRPC) SetDefaults() {
|
||||
c.Endpoint = "localhost:4317"
|
||||
}
|
||||
|
||||
// OtelHTTP provides configuration settings for the HTTP open-telemetry.
|
||||
type OtelHTTP struct {
|
||||
Endpoint string `description:"Sets the HTTP endpoint (scheme://host:port/path) of the collector." json:"endpoint,omitempty" toml:"endpoint,omitempty" yaml:"endpoint,omitempty"`
|
||||
TLS *ClientTLS `description:"Defines client transport security parameters." json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" export:"true"`
|
||||
Headers map[string]string `description:"Headers sent with payload." json:"headers,omitempty" toml:"headers,omitempty" yaml:"headers,omitempty"`
|
||||
}
|
||||
|
||||
// SetDefaults sets the default values.
|
||||
func (c *OtelHTTP) SetDefaults() {
|
||||
c.Endpoint = "https://localhost:4318"
|
||||
}
|
||||
|
26
pkg/types/otel.go
Normal file
26
pkg/types/otel.go
Normal file
@ -0,0 +1,26 @@
|
||||
package types
|
||||
|
||||
// OTelGRPC provides configuration settings for the gRPC open-telemetry.
|
||||
type OTelGRPC struct {
|
||||
Endpoint string `description:"Sets the gRPC endpoint (host:port) of the collector." json:"endpoint,omitempty" toml:"endpoint,omitempty" yaml:"endpoint,omitempty"`
|
||||
Insecure bool `description:"Disables client transport security for the exporter." json:"insecure,omitempty" toml:"insecure,omitempty" yaml:"insecure,omitempty" export:"true"`
|
||||
TLS *ClientTLS `description:"Defines client transport security parameters." json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" export:"true"`
|
||||
Headers map[string]string `description:"Headers sent with payload." json:"headers,omitempty" toml:"headers,omitempty" yaml:"headers,omitempty"`
|
||||
}
|
||||
|
||||
// SetDefaults sets the default values.
|
||||
func (o *OTelGRPC) SetDefaults() {
|
||||
o.Endpoint = "localhost:4317"
|
||||
}
|
||||
|
||||
// OTelHTTP provides configuration settings for the HTTP open-telemetry.
|
||||
type OTelHTTP struct {
|
||||
Endpoint string `description:"Sets the HTTP endpoint (scheme://host:port/path) of the collector." json:"endpoint,omitempty" toml:"endpoint,omitempty" yaml:"endpoint,omitempty"`
|
||||
TLS *ClientTLS `description:"Defines client transport security parameters." json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" export:"true"`
|
||||
Headers map[string]string `description:"Headers sent with payload." json:"headers,omitempty" toml:"headers,omitempty" yaml:"headers,omitempty"`
|
||||
}
|
||||
|
||||
// SetDefaults sets the default values.
|
||||
func (o *OTelHTTP) SetDefaults() {
|
||||
o.Endpoint = "https://localhost:4318"
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package opentelemetry
|
||||
package types
|
||||
|
||||
import (
|
||||
"context"
|
||||
@ -9,7 +9,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/traefik/traefik/v3/pkg/types"
|
||||
"github.com/traefik/traefik/v3/pkg/version"
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
@ -18,26 +17,26 @@ import (
|
||||
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
sdktrace "go.opentelemetry.io/otel/sdk/trace"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.27.0"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/encoding/gzip"
|
||||
)
|
||||
|
||||
// Config provides configuration settings for the open-telemetry tracer.
|
||||
type Config struct {
|
||||
GRPC *types.OtelGRPC `description:"gRPC configuration for the OpenTelemetry collector." json:"grpc,omitempty" toml:"grpc,omitempty" yaml:"grpc,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
||||
HTTP *types.OtelHTTP `description:"HTTP configuration for the OpenTelemetry collector." json:"http,omitempty" toml:"http,omitempty" yaml:"http,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
||||
// OTelTracing provides configuration settings for the open-telemetry tracer.
|
||||
type OTelTracing struct {
|
||||
GRPC *OTelGRPC `description:"gRPC configuration for the OpenTelemetry collector." json:"grpc,omitempty" toml:"grpc,omitempty" yaml:"grpc,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
||||
HTTP *OTelHTTP `description:"HTTP configuration for the OpenTelemetry collector." json:"http,omitempty" toml:"http,omitempty" yaml:"http,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
|
||||
}
|
||||
|
||||
// SetDefaults sets the default values.
|
||||
func (c *Config) SetDefaults() {
|
||||
c.HTTP = &types.OtelHTTP{}
|
||||
func (c *OTelTracing) SetDefaults() {
|
||||
c.HTTP = &OTelHTTP{}
|
||||
c.HTTP.SetDefaults()
|
||||
}
|
||||
|
||||
// Setup sets up the tracer.
|
||||
func (c *Config) Setup(serviceName string, sampleRate float64, globalAttributes map[string]string) (trace.Tracer, io.Closer, error) {
|
||||
func (c *OTelTracing) Setup(serviceName string, sampleRate float64, globalAttributes map[string]string) (trace.Tracer, io.Closer, error) {
|
||||
var (
|
||||
err error
|
||||
exporter *otlptrace.Exporter
|
||||
@ -87,7 +86,7 @@ func (c *Config) Setup(serviceName string, sampleRate float64, globalAttributes
|
||||
return tracerProvider.Tracer("github.com/traefik/traefik"), &tpCloser{provider: tracerProvider}, err
|
||||
}
|
||||
|
||||
func (c *Config) setupHTTPExporter() (*otlptrace.Exporter, error) {
|
||||
func (c *OTelTracing) setupHTTPExporter() (*otlptrace.Exporter, error) {
|
||||
endpoint, err := url.Parse(c.HTTP.Endpoint)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid collector endpoint %q: %w", c.HTTP.Endpoint, err)
|
||||
@ -119,7 +118,7 @@ func (c *Config) setupHTTPExporter() (*otlptrace.Exporter, error) {
|
||||
return otlptrace.New(context.Background(), otlptracehttp.NewClient(opts...))
|
||||
}
|
||||
|
||||
func (c *Config) setupGRPCExporter() (*otlptrace.Exporter, error) {
|
||||
func (c *OTelTracing) setupGRPCExporter() (*otlptrace.Exporter, error) {
|
||||
host, port, err := net.SplitHostPort(c.GRPC.Endpoint)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid collector endpoint %q: %w", c.GRPC.Endpoint, err)
|
Loading…
x
Reference in New Issue
Block a user