diff --git a/cmd/traefik/traefik.go b/cmd/traefik/traefik.go index f3e01f7b8..0ac89fb46 100644 --- a/cmd/traefik/traefik.go +++ b/cmd/traefik/traefik.go @@ -5,6 +5,7 @@ import ( "crypto/x509" "encoding/json" "fmt" + "io" stdlog "log" "net/http" "os" @@ -43,9 +44,9 @@ import ( "github.com/traefik/traefik/v3/pkg/tcp" traefiktls "github.com/traefik/traefik/v3/pkg/tls" "github.com/traefik/traefik/v3/pkg/tracing" - "github.com/traefik/traefik/v3/pkg/tracing/jaeger" "github.com/traefik/traefik/v3/pkg/types" "github.com/traefik/traefik/v3/pkg/version" + "go.opentelemetry.io/otel/trace" ) func main() { @@ -265,10 +266,9 @@ func setupServer(staticConfiguration *static.Configuration) (*server.Server, err managerFactory := service.NewManagerFactory(*staticConfiguration, routinesPool, metricsRegistry, roundTripperManager, acmeHTTPHandler) // Router factory - accessLog := setupAccessLog(staticConfiguration.AccessLog) - tracer := setupTracing(staticConfiguration.Tracing) + tracer, tracerCloser := setupTracing(staticConfiguration.Tracing) chainBuilder := middleware.NewChainBuilder(metricsRegistry, accessLog, tracer) routerFactory := server.NewRouterFactory(*staticConfiguration, managerFactory, tlsManager, chainBuilder, pluginBuilder, metricsRegistry, dialerManager) @@ -351,7 +351,7 @@ func setupServer(staticConfiguration *static.Configuration) (*server.Server, err } }) - return server.NewServer(routinesPool, serverEntryPointsTCP, serverEntryPointsUDP, watcher, chainBuilder, accessLog), nil + return server.NewServer(routinesPool, serverEntryPointsTCP, serverEntryPointsUDP, watcher, chainBuilder, accessLog, tracerCloser), nil } func getHTTPChallengeHandler(acmeProviders []*acme.Provider, httpChallengeProvider http.Handler) http.Handler { @@ -564,78 +564,18 @@ func setupAccessLog(conf *types.AccessLog) *accesslog.Handler { return accessLoggerMiddleware } -func setupTracing(conf *static.Tracing) *tracing.Tracing { +func setupTracing(conf *static.Tracing) (trace.Tracer, io.Closer) { if conf == nil { - return nil + return nil, nil } - var backend tracing.Backend - - if conf.Jaeger != nil { - backend = conf.Jaeger - } - - if conf.Zipkin != nil { - if backend != nil { - log.Error().Msg("Multiple tracing backend are not supported: cannot create Zipkin backend.") - } else { - backend = conf.Zipkin - } - } - - if conf.Datadog != nil { - if backend != nil { - log.Error().Msg("Multiple tracing backend are not supported: cannot create Datadog backend.") - } else { - backend = conf.Datadog - } - } - - if conf.Instana != nil { - if backend != nil { - log.Error().Msg("Multiple tracing backend are not supported: cannot create Instana backend.") - } else { - backend = conf.Instana - } - } - - if conf.Haystack != nil { - if backend != nil { - log.Error().Msg("Multiple tracing backend are not supported: cannot create Haystack backend.") - } else { - backend = conf.Haystack - } - } - - if conf.Elastic != nil { - if backend != nil { - log.Error().Msg("Multiple tracing backend are not supported: cannot create Elastic backend.") - } else { - backend = conf.Elastic - } - } - - if conf.OpenTelemetry != nil { - if backend != nil { - log.Error().Msg("Tracing backends are all mutually exclusive: cannot create OpenTelemetry backend.") - } else { - backend = conf.OpenTelemetry - } - } - - if backend == nil { - log.Debug().Msg("Could not initialize tracing, using Jaeger by default") - defaultBackend := &jaeger.Config{} - defaultBackend.SetDefaults() - backend = defaultBackend - } - - tracer, err := tracing.NewTracing(conf.ServiceName, conf.SpanNameLimit, backend) + tracer, closer, err := tracing.NewTracing(conf) if err != nil { log.Warn().Err(err).Msg("Unable to create tracer") - return nil + return nil, nil } - return tracer + + return tracer, closer } func checkNewVersion() { diff --git a/docs/content/migration/v2-to-v3.md b/docs/content/migration/v2-to-v3.md index dcc7505a1..70b27f820 100644 --- a/docs/content/migration/v2-to-v3.md +++ b/docs/content/migration/v2-to-v3.md @@ -394,3 +394,24 @@ One should use the `ContentType` middleware to enable the `Content-Type` header #### gRPC Metrics In v3, the reported status code for gRPC requests is now the value of the `Grpc-Status` header. + +#### Tracing + +In v3, the tracing feature has been revamped and is now powered exclusively by [OpenTelemetry](https://opentelemetry.io/ "Link to website of OTel") (OTel). +!!! warning "Important" + + Traefik v3 **no** longer supports direct output formats for specific vendors such as Instana, Jaeger, Zipkin, Haystack, Datadog, and Elastic. +Instead, it focuses on pure OpenTelemetry implementation, providing a unified and standardized approach for observability. + +Here are two possible transition strategies: + +1. OTLP Ingestion Endpoints: + + Most vendors now offer OpenTelemetry Protocol (OTLP) ingestion endpoints. + You can seamlessly integrate Traefik v3 with these endpoints to continue leveraging tracing capabilities. + +2. Legacy Stack Compatibility: + + For legacy stacks that cannot immediately upgrade to the latest vendor agents supporting OTLP ingestion, + using OpenTelemetry (OTel) collectors with appropriate exporters configuration is a viable solution. + This allows continued compatibility with the existing infrastructure. diff --git a/docs/content/observability/tracing/datadog.md b/docs/content/observability/tracing/datadog.md deleted file mode 100644 index fe14bc72f..000000000 --- a/docs/content/observability/tracing/datadog.md +++ /dev/null @@ -1,139 +0,0 @@ ---- -title: "Traefik Datadog Tracing Documentation" -description: "Traefik Proxy supports Datadog for tracing. Read the technical documentation to enable Datadog for observability." ---- - -# Datadog - -To enable the Datadog tracer: - -```yaml tab="File (YAML)" -tracing: - datadog: {} -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.datadog] -``` - -```bash tab="CLI" ---tracing.datadog=true -``` - -#### `localAgentHostPort` - -_Optional, Default="localhost:8126"_ - -Local Agent Host Port instructs the reporter to send spans to the Datadog Agent at this address (host:port). - -```yaml tab="File (YAML)" -tracing: - datadog: - localAgentHostPort: localhost:8126 -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.datadog] - localAgentHostPort = "localhost:8126" -``` - -```bash tab="CLI" ---tracing.datadog.localAgentHostPort=localhost:8126 -``` - -#### `localAgentSocket` - -_Optional, Default=""_ - -Local Agent Socket instructs the reporter to send spans to the Datadog Agent at this UNIX socket. - -```yaml tab="File (YAML)" -tracing: - datadog: - localAgentSocket: /var/run/datadog/apm.socket -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.datadog] - localAgentSocket = "/var/run/datadog/apm.socket" -``` - -```bash tab="CLI" ---tracing.datadog.localAgentSocket=/var/run/datadog/apm.socket -``` - -#### `debug` - -_Optional, Default=false_ - -Enables Datadog debug. - -```yaml tab="File (YAML)" -tracing: - datadog: - debug: true -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.datadog] - debug = true -``` - -```bash tab="CLI" ---tracing.datadog.debug=true -``` - -#### `globalTags` - -_Optional, Default=empty_ - -Applies a list of shared key:value tags on all spans. - -```yaml tab="File (YAML)" -tracing: - datadog: - globalTags: - tag1: foo - tag2: bar -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.datadog] - [tracing.datadog.globalTags] - tag1 = "foo" - tag2 = "bar" -``` - -```bash tab="CLI" ---tracing.datadog.globalTags.tag1=foo ---tracing.datadog.globalTags.tag2=bar -``` - -#### `prioritySampling` - -_Optional, Default=false_ - -Enables priority sampling. -When using distributed tracing, -this option must be enabled in order to get all the parts of a distributed trace sampled. - -```yaml tab="File (YAML)" -tracing: - datadog: - prioritySampling: true -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.datadog] - prioritySampling = true -``` - -```bash tab="CLI" ---tracing.datadog.prioritySampling=true -``` diff --git a/docs/content/observability/tracing/elastic.md b/docs/content/observability/tracing/elastic.md deleted file mode 100644 index 0cb0dccee..000000000 --- a/docs/content/observability/tracing/elastic.md +++ /dev/null @@ -1,93 +0,0 @@ ---- -title: "Traefik Elastic Documentation" -description: "Traefik supports several tracing backends, including Elastic. Learn how to implement it for observability in Traefik Proxy. Read the technical documentation." ---- - -# Elastic - -To enable the Elastic tracer: - -```yaml tab="File (YAML)" -tracing: - elastic: {} -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.elastic] -``` - -```bash tab="CLI" ---tracing.elastic=true -``` - -#### `serverURL` - -_Optional, Default="http://localhost:8200"_ - -URL of the Elastic APM server. - -```yaml tab="File (YAML)" -tracing: - elastic: - serverURL: "http://apm:8200" -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.elastic] - serverURL = "http://apm:8200" -``` - -```bash tab="CLI" ---tracing.elastic.serverurl="http://apm:8200" -``` - -#### `secretToken` - -_Optional, Default=""_ - -Token used to connect to Elastic APM Server. - -```yaml tab="File (YAML)" -tracing: - elastic: - secretToken: "mytoken" -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.elastic] - secretToken = "mytoken" -``` - -```bash tab="CLI" ---tracing.elastic.secrettoken="mytoken" -``` - -#### `serviceEnvironment` - -_Optional, Default=""_ - -Environment's name where Traefik is deployed in, e.g. `production` or `staging`. - -```yaml tab="File (YAML)" -tracing: - elastic: - serviceEnvironment: "production" -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.elastic] - serviceEnvironment = "production" -``` - -```bash tab="CLI" ---tracing.elastic.serviceenvironment="production" -``` - -### Further - -Additional configuration of Elastic APM Go agent can be done using environment variables. -See [APM Go agent reference](https://www.elastic.co/guide/en/apm/agent/go/current/configuration.html). diff --git a/docs/content/observability/tracing/haystack.md b/docs/content/observability/tracing/haystack.md deleted file mode 100644 index af9945ed7..000000000 --- a/docs/content/observability/tracing/haystack.md +++ /dev/null @@ -1,176 +0,0 @@ ---- -title: "Traefik Haystack Documentation" -description: "Traefik supports several tracing backends, including Haystack. Learn how to implement it for observability in Traefik Proxy. Read the technical documentation." ---- - -# Haystack - -To enable the Haystack tracer: - -```yaml tab="File (YAML)" -tracing: - haystack: {} -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.haystack] -``` - -```bash tab="CLI" ---tracing.haystack=true -``` - -#### `localAgentHost` - -_Required, Default="127.0.0.1"_ - -Local Agent Host instructs reporter to send spans to the Haystack Agent at this address. - -```yaml tab="File (YAML)" -tracing: - haystack: - localAgentHost: 127.0.0.1 -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.haystack] - localAgentHost = "127.0.0.1" -``` - -```bash tab="CLI" ---tracing.haystack.localAgentHost=127.0.0.1 -``` - -#### `localAgentPort` - -_Required, Default=35000_ - -Local Agent Port instructs reporter to send spans to the Haystack Agent at this port. - -```yaml tab="File (YAML)" -tracing: - haystack: - localAgentPort: 35000 -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.haystack] - localAgentPort = 35000 -``` - -```bash tab="CLI" ---tracing.haystack.localAgentPort=35000 -``` - -#### `globalTag` - -_Optional, Default=empty_ - -Applies shared key:value tag on all spans. - -```yaml tab="File (YAML)" -tracing: - haystack: - globalTag: sample:test -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.haystack] - globalTag = "sample:test" -``` - -```bash tab="CLI" ---tracing.haystack.globalTag=sample:test -``` - -#### `traceIDHeaderName` - -_Optional, Default=empty_ - -Sets the header name used to store the trace ID. - -```yaml tab="File (YAML)" -tracing: - haystack: - traceIDHeaderName: Trace-ID -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.haystack] - traceIDHeaderName = "Trace-ID" -``` - -```bash tab="CLI" ---tracing.haystack.traceIDHeaderName=Trace-ID -``` - -#### `parentIDHeaderName` - -_Optional, Default=empty_ - -Sets the header name used to store the parent ID. - -```yaml tab="File (YAML)" -tracing: - haystack: - parentIDHeaderName: Parent-Message-ID -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.haystack] - parentIDHeaderName = "Parent-Message-ID" -``` - -```bash tab="CLI" ---tracing.haystack.parentIDHeaderName=Parent-Message-ID -``` - -#### `spanIDHeaderName` - -_Optional, Default=empty_ - -Sets the header name used to store the span ID. - -```yaml tab="File (YAML)" -tracing: - haystack: - spanIDHeaderName: Message-ID -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.haystack] - spanIDHeaderName = "Message-ID" -``` - -```bash tab="CLI" ---tracing.haystack.spanIDHeaderName=Message-ID -``` - -#### `baggagePrefixHeaderName` - -_Optional, Default=empty_ - -Sets the header name prefix used to store baggage items in a map. - -```yaml tab="File (YAML)" -tracing: - haystack: - baggagePrefixHeaderName: "sample" -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.haystack] - baggagePrefixHeaderName = "sample" -``` - -```bash tab="CLI" ---tracing.haystack.baggagePrefixHeaderName=sample -``` diff --git a/docs/content/observability/tracing/instana.md b/docs/content/observability/tracing/instana.md deleted file mode 100644 index 914d9d3f4..000000000 --- a/docs/content/observability/tracing/instana.md +++ /dev/null @@ -1,117 +0,0 @@ ---- -title: "Traefik Instana Documentation" -description: "Traefik supports several tracing backends, including Instana. Learn how to implement it for observability in Traefik Proxy. Read the technical documentation." ---- - -# Instana - -To enable the Instana tracer: - -```yaml tab="File (YAML)" -tracing: - instana: {} -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.instana] -``` - -```bash tab="CLI" ---tracing.instana=true -``` - -#### `localAgentHost` - -_Required, Default="127.0.0.1"_ - -Local Agent Host instructs reporter to send spans to the Instana Agent at this address. - -```yaml tab="File (YAML)" -tracing: - instana: - localAgentHost: 127.0.0.1 -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.instana] - localAgentHost = "127.0.0.1" -``` - -```bash tab="CLI" ---tracing.instana.localAgentHost=127.0.0.1 -``` - -#### `localAgentPort` - -_Required, Default=42699_ - -Local Agent port instructs reporter to send spans to the Instana Agent listening on this port. - -```yaml tab="File (YAML)" -tracing: - instana: - localAgentPort: 42699 -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.instana] - localAgentPort = 42699 -``` - -```bash tab="CLI" ---tracing.instana.localAgentPort=42699 -``` - -#### `logLevel` - -_Required, Default="info"_ - -Sets Instana tracer log level. - -Valid values are: - -- `error` -- `warn` -- `debug` -- `info` - -```yaml tab="File (YAML)" -tracing: - instana: - logLevel: info -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.instana] - logLevel = "info" -``` - -```bash tab="CLI" ---tracing.instana.logLevel=info -``` - -#### `enableAutoProfile` - -_Required, Default=false_ - -Enables [automatic profiling](https://www.ibm.com/docs/en/obi/current?topic=instana-profile-processes) for the Traefik process. - -```yaml tab="File (YAML)" -tracing: - instana: - enableAutoProfile: true -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.instana] - enableAutoProfile = true -``` - -```bash tab="CLI" ---tracing.instana.enableAutoProfile=true -``` diff --git a/docs/content/observability/tracing/jaeger.md b/docs/content/observability/tracing/jaeger.md deleted file mode 100644 index d40ffed6d..000000000 --- a/docs/content/observability/tracing/jaeger.md +++ /dev/null @@ -1,294 +0,0 @@ ---- -title: "Traefik Jaeger Documentation" -description: "Traefik supports several tracing backends, including Jaeger. Learn how to implement it for observability in Traefik Proxy. Read the technical documentation." ---- - -# Jaeger - -To enable the Jaeger tracer: - -```yaml tab="File (YAML)" -tracing: - jaeger: {} -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.jaeger] -``` - -```bash tab="CLI" ---tracing.jaeger=true -``` - -!!! warning - Traefik is able to send data over the compact thrift protocol to the [Jaeger agent](https://www.jaegertracing.io/docs/deployment/#agent) - or a [Jaeger collector](https://www.jaegertracing.io/docs/deployment/#collector). - -!!! info - All Jaeger configuration can be overridden by [environment variables](https://github.com/jaegertracing/jaeger-client-go#environment-variables) - -#### `samplingServerURL` - -_Required, Default="http://localhost:5778/sampling"_ - -Address of the Jaeger Agent HTTP sampling server. - -```yaml tab="File (YAML)" -tracing: - jaeger: - samplingServerURL: http://localhost:5778/sampling -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.jaeger] - samplingServerURL = "http://localhost:5778/sampling" -``` - -```bash tab="CLI" ---tracing.jaeger.samplingServerURL=http://localhost:5778/sampling -``` - -#### `samplingType` - -_Required, Default="const"_ - -Type of the sampler. - -Valid values are: - -- `const` -- `probabilistic` -- `rateLimiting` - -```yaml tab="File (YAML)" -tracing: - jaeger: - samplingType: const -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.jaeger] - samplingType = "const" -``` - -```bash tab="CLI" ---tracing.jaeger.samplingType=const -``` - -#### `samplingParam` - -_Required, Default=1.0_ - -Value passed to the sampler. - -Valid values are: - -- for `const` sampler, 0 or 1 for always false/true respectively -- for `probabilistic` sampler, a probability between 0 and 1 -- for `rateLimiting` sampler, the number of spans per second - -```yaml tab="File (YAML)" -tracing: - jaeger: - samplingParam: 1.0 -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.jaeger] - samplingParam = 1.0 -``` - -```bash tab="CLI" ---tracing.jaeger.samplingParam=1.0 -``` - -#### `localAgentHostPort` - -_Required, Default="127.0.0.1:6831"_ - -Local Agent Host Port instructs the reporter to send spans to the Jaeger Agent at this address (host:port). - -```yaml tab="File (YAML)" -tracing: - jaeger: - localAgentHostPort: 127.0.0.1:6831 -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.jaeger] - localAgentHostPort = "127.0.0.1:6831" -``` - -```bash tab="CLI" ---tracing.jaeger.localAgentHostPort=127.0.0.1:6831 -``` - -#### `gen128Bit` - -_Optional, Default=false_ - -Generates 128 bits trace IDs, compatible with OpenCensus. - -```yaml tab="File (YAML)" -tracing: - jaeger: - gen128Bit: true -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.jaeger] - gen128Bit = true -``` - -```bash tab="CLI" ---tracing.jaeger.gen128Bit -``` - -#### `propagation` - -_Required, Default="jaeger"_ - -Sets the propagation header type. - -Valid values are: - -- `jaeger`, jaeger's default trace header. -- `b3`, compatible with OpenZipkin - -```yaml tab="File (YAML)" -tracing: - jaeger: - propagation: jaeger -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.jaeger] - propagation = "jaeger" -``` - -```bash tab="CLI" ---tracing.jaeger.propagation=jaeger -``` - -#### `traceContextHeaderName` - -_Required, Default="uber-trace-id"_ - -HTTP header name used to propagate tracing context. -This must be in lower-case to avoid mismatches when decoding incoming headers. - -```yaml tab="File (YAML)" -tracing: - jaeger: - traceContextHeaderName: uber-trace-id -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.jaeger] - traceContextHeaderName = "uber-trace-id" -``` - -```bash tab="CLI" ---tracing.jaeger.traceContextHeaderName=uber-trace-id -``` - -### disableAttemptReconnecting - -_Optional, Default=true_ - -Disables the UDP connection helper that periodically re-resolves the agent's hostname and reconnects if there was a change. -Enabling the re-resolving of UDP address make the client more robust in Kubernetes deployments. - -```yaml tab="File (YAML)" -tracing: - jaeger: - disableAttemptReconnecting: false -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.jaeger] - disableAttemptReconnecting = false -``` - -```bash tab="CLI" ---tracing.jaeger.disableAttemptReconnecting=false -``` - -### `collector` -#### `endpoint` - -_Optional, Default=""_ - -Collector Endpoint instructs the reporter to send spans to the Jaeger Collector at this URL. - -```yaml tab="File (YAML)" -tracing: - jaeger: - collector: - endpoint: http://127.0.0.1:14268/api/traces?format=jaeger.thrift -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.jaeger.collector] - endpoint = "http://127.0.0.1:14268/api/traces?format=jaeger.thrift" -``` - -```bash tab="CLI" ---tracing.jaeger.collector.endpoint=http://127.0.0.1:14268/api/traces?format=jaeger.thrift -``` - -#### `user` - -_Optional, Default=""_ - -User instructs the reporter to include a user for basic HTTP authentication when sending spans to the Jaeger Collector. - -```yaml tab="File (YAML)" -tracing: - jaeger: - collector: - user: my-user -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.jaeger.collector] - user = "my-user" -``` - -```bash tab="CLI" ---tracing.jaeger.collector.user=my-user -``` - -#### `password` - -_Optional, Default=""_ - -Password instructs the reporter to include a password for basic HTTP authentication when sending spans to the Jaeger Collector. - -```yaml tab="File (YAML)" -tracing: - jaeger: - collector: - password: my-password -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.jaeger.collector] - password = "my-password" -``` - -```bash tab="CLI" ---tracing.jaeger.collector.password=my-password -``` diff --git a/docs/content/observability/tracing/opentelemetry.md b/docs/content/observability/tracing/opentelemetry.md index d39e09b58..52b37a0a5 100644 --- a/docs/content/observability/tracing/opentelemetry.md +++ b/docs/content/observability/tracing/opentelemetry.md @@ -9,122 +9,75 @@ To enable the OpenTelemetry tracer: ```yaml tab="File (YAML)" tracing: - openTelemetry: {} + otlp: {} ``` ```toml tab="File (TOML)" [tracing] - [tracing.openTelemetry] + [tracing.otlp] ``` ```bash tab="CLI" ---tracing.openTelemetry=true +--tracing.otlp=true ``` -!!! info "The OpenTelemetry trace reporter will export traces to the collector using HTTP by default, see the [gRPC Section](#grpc-configuration) to use gRPC." +!!! info "The OpenTelemetry trace reporter will export traces to the collector using HTTP by default (http://localhost:4318/v1/traces), +see the [gRPC Section](#grpc-configuration) to use gRPC." !!! info "Trace sampling" - By default, the OpenTelemetry trace reporter will sample 100% of traces. + By default, the OpenTelemetry trace reporter will sample 100% of traces. See [OpenTelemetry's SDK configuration](https://opentelemetry.io/docs/reference/specification/sdk-environment-variables/#general-sdk-configuration) to customize the sampling strategy. -#### `address` +### HTTP configuration -_Required, Default="localhost:4318", Format="`:`"_ +_Optional_ -Address of the OpenTelemetry Collector to send spans to. +This instructs the reporter to send spans to the OpenTelemetry Collector using HTTP. ```yaml tab="File (YAML)" tracing: - openTelemetry: - address: localhost:4318 + otlp: + http: {} ``` ```toml tab="File (TOML)" [tracing] - [tracing.openTelemetry] - address = "localhost:4318" + [tracing.otlp.http] ``` ```bash tab="CLI" ---tracing.openTelemetry.address=localhost:4318 +--tracing.otlp.http=true ``` -#### `headers` +#### `endpoint` -_Optional, Default={}_ +_Required, Default="http://localhost:4318/v1/traces", Format="`://:`"_ -Additional headers sent with spans by the reporter to the OpenTelemetry Collector. +URL of the OpenTelemetry Collector to send spans to. ```yaml tab="File (YAML)" tracing: - openTelemetry: - headers: - foo: bar - baz: buz + otlp: + http: + endpoint: http://localhost:4318/v1/traces ``` ```toml tab="File (TOML)" [tracing] - [tracing.openTelemetry.headers] - foo = "bar" - baz = "buz" + [tracing.otlp.http] + endpoint = "http://localhost:4318/v1/traces" ``` ```bash tab="CLI" ---tracing.openTelemetry.headers.foo=bar --tracing.openTelemetry.headers.baz=buz -``` - -#### `insecure` - -_Optional, Default=false_ - -Allows reporter to send spans to the OpenTelemetry Collector without using a secured protocol. - -```yaml tab="File (YAML)" -tracing: - openTelemetry: - insecure: true -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.openTelemetry] - insecure = true -``` - -```bash tab="CLI" ---tracing.openTelemetry.insecure=true -``` - -#### `path` - -_Required, Default="/v1/traces"_ - -Allows to override the default URL path used for sending traces. -This option has no effect when using gRPC transport. - -```yaml tab="File (YAML)" -tracing: - openTelemetry: - path: /foo/v1/traces -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.openTelemetry] - path = "/foo/v1/traces" -``` - -```bash tab="CLI" ---tracing.openTelemetry.path=/foo/v1/traces +--tracing.otlp.http.endpoint=http://localhost:4318/v1/traces ``` #### `tls` _Optional_ -Defines the TLS configuration used by the reporter to send spans to the OpenTelemetry Collector. +Defines the Client TLS configuration used by the reporter to send spans to the OpenTelemetry Collector. ##### `ca` @@ -135,18 +88,19 @@ it defaults to the system bundle. ```yaml tab="File (YAML)" tracing: - openTelemetry: - tls: - ca: path/to/ca.crt + otlp: + http: + tls: + ca: path/to/ca.crt ``` ```toml tab="File (TOML)" -[tracing.openTelemetry.tls] +[tracing.otlp.http.tls] ca = "path/to/ca.crt" ``` ```bash tab="CLI" ---tracing.openTelemetry.tls.ca=path/to/ca.crt +--tracing.otlp.http.tls.ca=path/to/ca.crt ``` ##### `cert` @@ -158,21 +112,22 @@ When using this option, setting the `key` option is required. ```yaml tab="File (YAML)" tracing: - openTelemetry: - tls: - cert: path/to/foo.cert - key: path/to/foo.key + otlp: + http: + tls: + cert: path/to/foo.cert + key: path/to/foo.key ``` ```toml tab="File (TOML)" -[tracing.openTelemetry.tls] +[tracing.otlp.http.tls] cert = "path/to/foo.cert" key = "path/to/foo.key" ``` ```bash tab="CLI" ---tracing.openTelemetry.tls.cert=path/to/foo.cert ---tracing.openTelemetry.tls.key=path/to/foo.key +--tracing.otlp.http.tls.cert=path/to/foo.cert +--tracing.otlp.http.tls.key=path/to/foo.key ``` ##### `key` @@ -184,21 +139,22 @@ When using this option, setting the `cert` option is required. ```yaml tab="File (YAML)" tracing: - openTelemetry: - tls: - cert: path/to/foo.cert - key: path/to/foo.key + otlp: + http: + tls: + cert: path/to/foo.cert + key: path/to/foo.key ``` ```toml tab="File (TOML)" -[tracing.openTelemetry.tls] +[tracing.otlp.http.tls] cert = "path/to/foo.cert" key = "path/to/foo.key" ``` ```bash tab="CLI" ---tracing.openTelemetry.tls.cert=path/to/foo.cert ---tracing.openTelemetry.tls.key=path/to/foo.key +--tracing.otlp.http.tls.cert=path/to/foo.cert +--tracing.otlp.http.tls.key=path/to/foo.key ``` ##### `insecureSkipVerify` @@ -210,18 +166,19 @@ the TLS connection to the OpenTelemetry Collector accepts any certificate presen ```yaml tab="File (YAML)" tracing: - openTelemetry: - tls: - insecureSkipVerify: true + otlp: + http: + tls: + insecureSkipVerify: true ``` ```toml tab="File (TOML)" -[tracing.openTelemetry.tls] +[tracing.otlp.http.tls] insecureSkipVerify = true ``` ```bash tab="CLI" ---tracing.openTelemetry.tls.insecureSkipVerify=true +--tracing.otlp.http.tls.insecureSkipVerify=true ``` #### gRPC configuration @@ -232,15 +189,168 @@ This instructs the reporter to send spans to the OpenTelemetry Collector using g ```yaml tab="File (YAML)" tracing: - openTelemetry: + otlp: grpc: {} ``` ```toml tab="File (TOML)" [tracing] - [tracing.openTelemetry.grpc] + [tracing.otlp.grpc] ``` ```bash tab="CLI" ---tracing.openTelemetry.grpc=true +--tracing.otlp.grpc=true +``` + +#### `endpoint` + +_Required, Default="localhost:4317", Format="`:`"_ + +Address of the OpenTelemetry Collector to send spans to. + +```yaml tab="File (YAML)" +tracing: + otlp: + grpc: + endpoint: localhost:4317 +``` + +```toml tab="File (TOML)" +[tracing] + [tracing.otlp.grpc] + endpoint = "localhost:4317" +``` + +```bash tab="CLI" +--tracing.otlp.grpc.endpoint=localhost:4317 +``` +#### `insecure` + +_Optional, Default=false_ + +Allows reporter to send spans to the OpenTelemetry Collector without using a secured protocol. + +```yaml tab="File (YAML)" +tracing: + otlp: + grpc: + insecure: true +``` + +```toml tab="File (TOML)" +[tracing] + [tracing.otlp.grpc] + insecure = true +``` + +```bash tab="CLI" +--tracing.otlp.grpc.insecure=true +``` + +#### `tls` + +_Optional_ + +Defines the Client TLS configuration used by the reporter to send spans 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)" +tracing: + otlp: + grpc: + tls: + ca: path/to/ca.crt +``` + +```toml tab="File (TOML)" +[tracing.otlp.grpc.tls] + ca = "path/to/ca.crt" +``` + +```bash tab="CLI" +--tracing.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)" +tracing: + otlp: + grpc: + tls: + cert: path/to/foo.cert + key: path/to/foo.key +``` + +```toml tab="File (TOML)" +[tracing.otlp.grpc.tls] + cert = "path/to/foo.cert" + key = "path/to/foo.key" +``` + +```bash tab="CLI" +--tracing.otlp.grpc.tls.cert=path/to/foo.cert +--tracing.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)" +tracing: + otlp: + grpc: + tls: + cert: path/to/foo.cert + key: path/to/foo.key +``` + +```toml tab="File (TOML)" +[tracing.otlp.grpc.tls] + cert = "path/to/foo.cert" + key = "path/to/foo.key" +``` + +```bash tab="CLI" +--tracing.otlp.grpc.tls.cert=path/to/foo.cert +--tracing.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)" +tracing: + otlp: + grpc: + tls: + insecureSkipVerify: true +``` + +```toml tab="File (TOML)" +[tracing.otlp.grpc.tls] + insecureSkipVerify = true +``` + +```bash tab="CLI" +--tracing.otlp.grpc.tls.insecureSkipVerify=true ``` diff --git a/docs/content/observability/tracing/overview.md b/docs/content/observability/tracing/overview.md index f4126274a..18b8c4f3e 100644 --- a/docs/content/observability/tracing/overview.md +++ b/docs/content/observability/tracing/overview.md @@ -10,21 +10,13 @@ Visualize the Requests Flow The tracing system allows developers to visualize call flows in their infrastructure. -Traefik uses OpenTracing, an open standard designed for distributed tracing. +Traefik uses [OpenTelemetry](https://opentelemetry.io/ "Link to website of OTel"), an open standard designed for distributed tracing. -Traefik supports seven tracing backends: +Please check our dedicated [OTel docs](./opentelemetry.md) to learn more. -- [Jaeger](./jaeger.md) -- [Zipkin](./zipkin.md) -- [Datadog](./datadog.md) -- [Instana](./instana.md) -- [Haystack](./haystack.md) -- [Elastic](./elastic.md) -- [OpenTelemetry](./opentelemetry.md) ## Configuration -By default, Traefik uses Jaeger as tracing backend. To enable the tracing: @@ -62,25 +54,71 @@ tracing: --tracing.serviceName=traefik ``` -#### `spanNameLimit` +#### `sampleRate` -_Required, Default=0_ +_Optional, Default=1.0_ -Span name limit allows for name truncation in case of very long names. -This can prevent certain tracing providers to drop traces that exceed their length limits. - -`0` means no truncation will occur. +The proportion of requests to trace, specified between 0.0 and 1.0. ```yaml tab="File (YAML)" tracing: - spanNameLimit: 150 + sampleRate: 0.2 ``` ```toml tab="File (TOML)" [tracing] - spanNameLimit = 150 + sampleRate = 0.2 ``` ```bash tab="CLI" ---tracing.spanNameLimit=150 +--tracing.sampleRate=0.2 +``` + +#### `headers` + +_Optional, Default={}_ + +Defines additional headers to be sent with the span's payload. + +```yaml tab="File (YAML)" +tracing: + headers: + foo: bar + baz: buz +``` + +```toml tab="File (TOML)" +[tracing] + [tracing.headers] + foo = "bar" + baz = "buz" +``` + +```bash tab="CLI" +--tracing.headers.foo=bar --tracing.headers.baz=buz +``` + +#### `globalAttributes` + +_Optional, Default=empty_ + +Applies a list of shared key:value attributes on all spans. + +```yaml tab="File (YAML)" +tracing: + globalAttributes: + attr1: foo + attr2: bar +``` + +```toml tab="File (TOML)" +[tracing] + [tracing.globalAttributes] + attr1 = "foo" + attr2 = "bar" +``` + +```bash tab="CLI" +--tracing.globalAttributes.attr1=foo +--tracing.globalAttributes.attr2=bar ``` diff --git a/docs/content/observability/tracing/zipkin.md b/docs/content/observability/tracing/zipkin.md deleted file mode 100644 index 146dae6e1..000000000 --- a/docs/content/observability/tracing/zipkin.md +++ /dev/null @@ -1,110 +0,0 @@ ---- -title: "Traefik Zipkin Documentation" -description: "Traefik supports several tracing backends, including Zipkin. Learn how to implement it for observability in Traefik Proxy. Read the technical documentation." ---- - -# Zipkin - -To enable the Zipkin tracer: - -```yaml tab="File (YAML)" -tracing: - zipkin: {} -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.zipkin] -``` - -```bash tab="CLI" ---tracing.zipkin=true -``` - -#### `httpEndpoint` - -_Required, Default="http://localhost:9411/api/v2/spans"_ - -HTTP endpoint used to send data. - -```yaml tab="File (YAML)" -tracing: - zipkin: - httpEndpoint: http://localhost:9411/api/v2/spans -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.zipkin] - httpEndpoint = "http://localhost:9411/api/v2/spans" -``` - -```bash tab="CLI" ---tracing.zipkin.httpEndpoint=http://localhost:9411/api/v2/spans -``` - -#### `sameSpan` - -_Optional, Default=false_ - -Uses SameSpan RPC style traces. - -```yaml tab="File (YAML)" -tracing: - zipkin: - sameSpan: true -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.zipkin] - sameSpan = true -``` - -```bash tab="CLI" ---tracing.zipkin.sameSpan=true -``` - -#### `id128Bit` - -_Optional, Default=true_ - -Uses 128 bits trace IDs. - -```yaml tab="File (YAML)" -tracing: - zipkin: - id128Bit: false -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.zipkin] - id128Bit = false -``` - -```bash tab="CLI" ---tracing.zipkin.id128Bit=false -``` - -#### `sampleRate` - -_Required, Default=1.0_ - -The proportion of requests to trace, specified between 0.0 and 1.0. - -```yaml tab="File (YAML)" -tracing: - zipkin: - sampleRate: 0.2 -``` - -```toml tab="File (TOML)" -[tracing] - [tracing.zipkin] - sampleRate = 0.2 -``` - -```bash tab="CLI" ---tracing.zipkin.sampleRate=0.2 -``` diff --git a/docs/content/reference/static-configuration/cli-ref.md b/docs/content/reference/static-configuration/cli-ref.md index 8e64fd2ae..efb874437 100644 --- a/docs/content/reference/static-configuration/cli-ref.md +++ b/docs/content/reference/static-configuration/cli-ref.md @@ -987,170 +987,50 @@ Defines the allowed SPIFFE trust domain. `--tracing`: OpenTracing configuration. (Default: ```false```) -`--tracing.datadog`: -Settings for Datadog. (Default: ```false```) +`--tracing.globalattributes.`: +Defines additional attributes (key:value) on all spans. -`--tracing.datadog.bagageprefixheadername`: -Sets the header name prefix used to store baggage items in a map. - -`--tracing.datadog.debug`: -Enables Datadog debug. (Default: ```false```) - -`--tracing.datadog.globaltags.`: -Sets a list of key:value tags on all spans. - -`--tracing.datadog.localagenthostport`: -Sets the Datadog Agent host:port. (Default: ```localhost:8126```) - -`--tracing.datadog.localagentsocket`: -Sets the socket for the Datadog Agent. - -`--tracing.datadog.parentidheadername`: -Sets the header name used to store the parent ID. - -`--tracing.datadog.prioritysampling`: -Enables priority sampling. When using distributed tracing, this option must be enabled in order to get all the parts of a distributed trace sampled. (Default: ```false```) - -`--tracing.datadog.samplingpriorityheadername`: -Sets the header name used to store the sampling priority. - -`--tracing.datadog.traceidheadername`: -Sets the header name used to store the trace ID. - -`--tracing.elastic`: -Settings for Elastic. (Default: ```false```) - -`--tracing.elastic.secrettoken`: -Sets the token used to connect to Elastic APM Server. - -`--tracing.elastic.serverurl`: -Sets the URL of the Elastic APM server. - -`--tracing.elastic.serviceenvironment`: -Sets the name of the environment Traefik is deployed in, e.g. 'production' or 'staging'. - -`--tracing.haystack`: -Settings for Haystack. (Default: ```false```) - -`--tracing.haystack.baggageprefixheadername`: -Sets the header name prefix used to store baggage items in a map. - -`--tracing.haystack.globaltag`: -Sets a key:value tag on all spans. - -`--tracing.haystack.localagenthost`: -Sets the Haystack Agent host. (Default: ```127.0.0.1```) - -`--tracing.haystack.localagentport`: -Sets the Haystack Agent port. (Default: ```35000```) - -`--tracing.haystack.parentidheadername`: -Sets the header name used to store the parent ID. - -`--tracing.haystack.spanidheadername`: -Sets the header name used to store the span ID. - -`--tracing.haystack.traceidheadername`: -Sets the header name used to store the trace ID. - -`--tracing.instana`: -Settings for Instana. (Default: ```false```) - -`--tracing.instana.enableautoprofile`: -Enables automatic profiling for the Traefik process. (Default: ```false```) - -`--tracing.instana.localagenthost`: -Sets the Instana Agent host. - -`--tracing.instana.localagentport`: -Sets the Instana Agent port. (Default: ```42699```) - -`--tracing.instana.loglevel`: -Sets the log level for the Instana tracer. ('error','warn','info','debug') (Default: ```info```) - -`--tracing.jaeger`: -Settings for Jaeger. (Default: ```false```) - -`--tracing.jaeger.collector.endpoint`: -Instructs reporter to send spans to jaeger-collector at this URL. - -`--tracing.jaeger.collector.password`: -Password for basic http authentication when sending spans to jaeger-collector. - -`--tracing.jaeger.collector.user`: -User for basic http authentication when sending spans to jaeger-collector. - -`--tracing.jaeger.disableattemptreconnecting`: -Disables the periodic re-resolution of the agent's hostname and reconnection if there was a change. (Default: ```true```) - -`--tracing.jaeger.gen128bit`: -Generates 128 bits span IDs. (Default: ```false```) - -`--tracing.jaeger.localagenthostport`: -Sets the Jaeger Agent host:port. (Default: ```127.0.0.1:6831```) - -`--tracing.jaeger.propagation`: -Sets the propagation format (jaeger/b3). (Default: ```jaeger```) - -`--tracing.jaeger.samplingparam`: -Sets the sampling parameter. (Default: ```1.000000```) - -`--tracing.jaeger.samplingserverurl`: -Sets the sampling server URL. (Default: ```http://localhost:5778/sampling```) - -`--tracing.jaeger.samplingtype`: -Sets the sampling type. (Default: ```const```) - -`--tracing.jaeger.tracecontextheadername`: -Sets the header name used to store the trace ID. (Default: ```uber-trace-id```) - -`--tracing.opentelemetry`: -Settings for OpenTelemetry. (Default: ```false```) - -`--tracing.opentelemetry.address`: -Sets the address (host:port) of the collector endpoint. (Default: ```localhost:4318```) - -`--tracing.opentelemetry.grpc`: -gRPC specific configuration for the OpenTelemetry collector. (Default: ```true```) - -`--tracing.opentelemetry.headers.`: +`--tracing.headers.`: Defines additional headers to be sent with the payloads. -`--tracing.opentelemetry.insecure`: +`--tracing.otlp`: +Settings for OpenTelemetry. (Default: ```false```) + +`--tracing.otlp.grpc.endpoint`: +Sets the gRPC endpoint (host:port) of the collector. (Default: ```localhost:4317```) + +`--tracing.otlp.grpc.insecure`: Disables client transport security for the exporter. (Default: ```false```) -`--tracing.opentelemetry.path`: -Sets the URL path of the collector endpoint. - -`--tracing.opentelemetry.tls.ca`: +`--tracing.otlp.grpc.tls.ca`: TLS CA -`--tracing.opentelemetry.tls.cert`: +`--tracing.otlp.grpc.tls.cert`: TLS cert -`--tracing.opentelemetry.tls.insecureskipverify`: +`--tracing.otlp.grpc.tls.insecureskipverify`: TLS insecure skip verify (Default: ```false```) -`--tracing.opentelemetry.tls.key`: +`--tracing.otlp.grpc.tls.key`: TLS key +`--tracing.otlp.http.endpoint`: +Sets the HTTP endpoint (scheme://host:port/v1/traces) of the collector. (Default: ```localhost:4318```) + +`--tracing.otlp.http.tls.ca`: +TLS CA + +`--tracing.otlp.http.tls.cert`: +TLS cert + +`--tracing.otlp.http.tls.insecureskipverify`: +TLS insecure skip verify (Default: ```false```) + +`--tracing.otlp.http.tls.key`: +TLS key + +`--tracing.samplerate`: +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```) - -`--tracing.spannamelimit`: -Set the maximum character limit for Span names (default 0 = no limit). (Default: ```0```) - -`--tracing.zipkin`: -Settings for Zipkin. (Default: ```false```) - -`--tracing.zipkin.httpendpoint`: -Sets the HTTP Endpoint to report traces to. (Default: ```http://localhost:9411/api/v2/spans```) - -`--tracing.zipkin.id128bit`: -Uses 128 bits root span IDs. (Default: ```true```) - -`--tracing.zipkin.samespan`: -Uses SameSpan RPC style traces. (Default: ```false```) - -`--tracing.zipkin.samplerate`: -Sets the rate between 0.0 and 1.0 of requests to trace. (Default: ```1.000000```) diff --git a/docs/content/reference/static-configuration/env-ref.md b/docs/content/reference/static-configuration/env-ref.md index 36dd4040c..10659e2e1 100644 --- a/docs/content/reference/static-configuration/env-ref.md +++ b/docs/content/reference/static-configuration/env-ref.md @@ -987,170 +987,50 @@ Defines the allowed SPIFFE trust domain. `TRAEFIK_TRACING`: OpenTracing configuration. (Default: ```false```) -`TRAEFIK_TRACING_DATADOG`: -Settings for Datadog. (Default: ```false```) +`TRAEFIK_TRACING_GLOBALATTRIBUTES_`: +Defines additional attributes (key:value) on all spans. -`TRAEFIK_TRACING_DATADOG_BAGAGEPREFIXHEADERNAME`: -Sets the header name prefix used to store baggage items in a map. - -`TRAEFIK_TRACING_DATADOG_DEBUG`: -Enables Datadog debug. (Default: ```false```) - -`TRAEFIK_TRACING_DATADOG_GLOBALTAGS_`: -Sets a list of key:value tags on all spans. - -`TRAEFIK_TRACING_DATADOG_LOCALAGENTHOSTPORT`: -Sets the Datadog Agent host:port. (Default: ```localhost:8126```) - -`TRAEFIK_TRACING_DATADOG_LOCALAGENTSOCKET`: -Sets the socket for the Datadog Agent. - -`TRAEFIK_TRACING_DATADOG_PARENTIDHEADERNAME`: -Sets the header name used to store the parent ID. - -`TRAEFIK_TRACING_DATADOG_PRIORITYSAMPLING`: -Enables priority sampling. When using distributed tracing, this option must be enabled in order to get all the parts of a distributed trace sampled. (Default: ```false```) - -`TRAEFIK_TRACING_DATADOG_SAMPLINGPRIORITYHEADERNAME`: -Sets the header name used to store the sampling priority. - -`TRAEFIK_TRACING_DATADOG_TRACEIDHEADERNAME`: -Sets the header name used to store the trace ID. - -`TRAEFIK_TRACING_ELASTIC`: -Settings for Elastic. (Default: ```false```) - -`TRAEFIK_TRACING_ELASTIC_SECRETTOKEN`: -Sets the token used to connect to Elastic APM Server. - -`TRAEFIK_TRACING_ELASTIC_SERVERURL`: -Sets the URL of the Elastic APM server. - -`TRAEFIK_TRACING_ELASTIC_SERVICEENVIRONMENT`: -Sets the name of the environment Traefik is deployed in, e.g. 'production' or 'staging'. - -`TRAEFIK_TRACING_HAYSTACK`: -Settings for Haystack. (Default: ```false```) - -`TRAEFIK_TRACING_HAYSTACK_BAGGAGEPREFIXHEADERNAME`: -Sets the header name prefix used to store baggage items in a map. - -`TRAEFIK_TRACING_HAYSTACK_GLOBALTAG`: -Sets a key:value tag on all spans. - -`TRAEFIK_TRACING_HAYSTACK_LOCALAGENTHOST`: -Sets the Haystack Agent host. (Default: ```127.0.0.1```) - -`TRAEFIK_TRACING_HAYSTACK_LOCALAGENTPORT`: -Sets the Haystack Agent port. (Default: ```35000```) - -`TRAEFIK_TRACING_HAYSTACK_PARENTIDHEADERNAME`: -Sets the header name used to store the parent ID. - -`TRAEFIK_TRACING_HAYSTACK_SPANIDHEADERNAME`: -Sets the header name used to store the span ID. - -`TRAEFIK_TRACING_HAYSTACK_TRACEIDHEADERNAME`: -Sets the header name used to store the trace ID. - -`TRAEFIK_TRACING_INSTANA`: -Settings for Instana. (Default: ```false```) - -`TRAEFIK_TRACING_INSTANA_ENABLEAUTOPROFILE`: -Enables automatic profiling for the Traefik process. (Default: ```false```) - -`TRAEFIK_TRACING_INSTANA_LOCALAGENTHOST`: -Sets the Instana Agent host. - -`TRAEFIK_TRACING_INSTANA_LOCALAGENTPORT`: -Sets the Instana Agent port. (Default: ```42699```) - -`TRAEFIK_TRACING_INSTANA_LOGLEVEL`: -Sets the log level for the Instana tracer. ('error','warn','info','debug') (Default: ```info```) - -`TRAEFIK_TRACING_JAEGER`: -Settings for Jaeger. (Default: ```false```) - -`TRAEFIK_TRACING_JAEGER_COLLECTOR_ENDPOINT`: -Instructs reporter to send spans to jaeger-collector at this URL. - -`TRAEFIK_TRACING_JAEGER_COLLECTOR_PASSWORD`: -Password for basic http authentication when sending spans to jaeger-collector. - -`TRAEFIK_TRACING_JAEGER_COLLECTOR_USER`: -User for basic http authentication when sending spans to jaeger-collector. - -`TRAEFIK_TRACING_JAEGER_DISABLEATTEMPTRECONNECTING`: -Disables the periodic re-resolution of the agent's hostname and reconnection if there was a change. (Default: ```true```) - -`TRAEFIK_TRACING_JAEGER_GEN128BIT`: -Generates 128 bits span IDs. (Default: ```false```) - -`TRAEFIK_TRACING_JAEGER_LOCALAGENTHOSTPORT`: -Sets the Jaeger Agent host:port. (Default: ```127.0.0.1:6831```) - -`TRAEFIK_TRACING_JAEGER_PROPAGATION`: -Sets the propagation format (jaeger/b3). (Default: ```jaeger```) - -`TRAEFIK_TRACING_JAEGER_SAMPLINGPARAM`: -Sets the sampling parameter. (Default: ```1.000000```) - -`TRAEFIK_TRACING_JAEGER_SAMPLINGSERVERURL`: -Sets the sampling server URL. (Default: ```http://localhost:5778/sampling```) - -`TRAEFIK_TRACING_JAEGER_SAMPLINGTYPE`: -Sets the sampling type. (Default: ```const```) - -`TRAEFIK_TRACING_JAEGER_TRACECONTEXTHEADERNAME`: -Sets the header name used to store the trace ID. (Default: ```uber-trace-id```) - -`TRAEFIK_TRACING_OPENTELEMETRY`: -Settings for OpenTelemetry. (Default: ```false```) - -`TRAEFIK_TRACING_OPENTELEMETRY_ADDRESS`: -Sets the address (host:port) of the collector endpoint. (Default: ```localhost:4318```) - -`TRAEFIK_TRACING_OPENTELEMETRY_GRPC`: -gRPC specific configuration for the OpenTelemetry collector. (Default: ```true```) - -`TRAEFIK_TRACING_OPENTELEMETRY_HEADERS_`: +`TRAEFIK_TRACING_HEADERS_`: Defines additional headers to be sent with the payloads. -`TRAEFIK_TRACING_OPENTELEMETRY_INSECURE`: +`TRAEFIK_TRACING_OTLP`: +Settings for OpenTelemetry. (Default: ```false```) + +`TRAEFIK_TRACING_OTLP_GRPC_ENDPOINT`: +Sets the gRPC endpoint (host:port) of the collector. (Default: ```localhost:4317```) + +`TRAEFIK_TRACING_OTLP_GRPC_INSECURE`: Disables client transport security for the exporter. (Default: ```false```) -`TRAEFIK_TRACING_OPENTELEMETRY_PATH`: -Sets the URL path of the collector endpoint. - -`TRAEFIK_TRACING_OPENTELEMETRY_TLS_CA`: +`TRAEFIK_TRACING_OTLP_GRPC_TLS_CA`: TLS CA -`TRAEFIK_TRACING_OPENTELEMETRY_TLS_CERT`: +`TRAEFIK_TRACING_OTLP_GRPC_TLS_CERT`: TLS cert -`TRAEFIK_TRACING_OPENTELEMETRY_TLS_INSECURESKIPVERIFY`: +`TRAEFIK_TRACING_OTLP_GRPC_TLS_INSECURESKIPVERIFY`: TLS insecure skip verify (Default: ```false```) -`TRAEFIK_TRACING_OPENTELEMETRY_TLS_KEY`: +`TRAEFIK_TRACING_OTLP_GRPC_TLS_KEY`: TLS key +`TRAEFIK_TRACING_OTLP_HTTP_ENDPOINT`: +Sets the HTTP endpoint (scheme://host:port/v1/traces) of the collector. (Default: ```localhost:4318```) + +`TRAEFIK_TRACING_OTLP_HTTP_TLS_CA`: +TLS CA + +`TRAEFIK_TRACING_OTLP_HTTP_TLS_CERT`: +TLS cert + +`TRAEFIK_TRACING_OTLP_HTTP_TLS_INSECURESKIPVERIFY`: +TLS insecure skip verify (Default: ```false```) + +`TRAEFIK_TRACING_OTLP_HTTP_TLS_KEY`: +TLS key + +`TRAEFIK_TRACING_SAMPLERATE`: +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```) - -`TRAEFIK_TRACING_SPANNAMELIMIT`: -Set the maximum character limit for Span names (default 0 = no limit). (Default: ```0```) - -`TRAEFIK_TRACING_ZIPKIN`: -Settings for Zipkin. (Default: ```false```) - -`TRAEFIK_TRACING_ZIPKIN_HTTPENDPOINT`: -Sets the HTTP Endpoint to report traces to. (Default: ```http://localhost:9411/api/v2/spans```) - -`TRAEFIK_TRACING_ZIPKIN_ID128BIT`: -Uses 128 bits root span IDs. (Default: ```true```) - -`TRAEFIK_TRACING_ZIPKIN_SAMESPAN`: -Uses SameSpan RPC style traces. (Default: ```false```) - -`TRAEFIK_TRACING_ZIPKIN_SAMPLERATE`: -Sets the rate between 0.0 and 1.0 of requests to trace. (Default: ```1.000000```) diff --git a/docs/content/reference/static-configuration/file.toml b/docs/content/reference/static-configuration/file.toml index 6d75b4dbc..58acc5ac7 100644 --- a/docs/content/reference/static-configuration/file.toml +++ b/docs/content/reference/static-configuration/file.toml @@ -367,68 +367,28 @@ [tracing] serviceName = "foobar" - spanNameLimit = 42 - [tracing.jaeger] - samplingServerURL = "foobar" - samplingType = "foobar" - samplingParam = 42.0 - localAgentHostPort = "foobar" - gen128Bit = true - propagation = "foobar" - traceContextHeaderName = "foobar" - disableAttemptReconnecting = true - [tracing.jaeger.collector] - endpoint = "foobar" - user = "foobar" - password = "foobar" - [tracing.zipkin] - httpEndpoint = "foobar" - sameSpan = true - id128Bit = true - sampleRate = 42.0 - [tracing.datadog] - localAgentHostPort = "foobar" - localAgentSocket = "foobar" - [tracing.datadog.globalTags] - tag1 = "foobar" - tag2 = "foobar" - debug = true - prioritySampling = true - traceIDHeaderName = "foobar" - parentIDHeaderName = "foobar" - samplingPriorityHeaderName = "foobar" - bagagePrefixHeaderName = "foobar" - [tracing.instana] - localAgentHost = "foobar" - localAgentPort = 42 - logLevel = "foobar" - enableAutoProfile = true - [tracing.haystack] - localAgentHost = "foobar" - localAgentPort = 42 - globalTag = "foobar" - traceIDHeaderName = "foobar" - parentIDHeaderName = "foobar" - spanIDHeaderName = "foobar" - baggagePrefixHeaderName = "foobar" - [tracing.elastic] - serverURL = "foobar" - secretToken = "foobar" - serviceEnvironment = "foobar" - [tracing.openTelemetry] - address = "foobar" + sampleRate = 42 + [tracing.headers] + header1 = "foobar" + header2 = "foobar" + [tracing.globalAttributes] + attr1 = "foobar" + attr2 = "foobar" + [tracing.otlp.grpc] + endpoint = "foobar" insecure = true - path = "foobar" - [tracing.openTelemetry.headers] - name0 = "foobar" - name1 = "foobar" - [tracing.openTelemetry.tls] + [tracing.otlp.grpc.tls] ca = "foobar" - caOptional = true cert = "foobar" key = "foobar" insecureSkipVerify = true - [tracing.openTelemetry.grpc] + [tracing.otlp.http] + endpoint = "foobar" + [tracing.otlp.http.tls] + ca = "foobar" + cert = "foobar" + key = "foobar" + insecureSkipVerify = true [hostResolver] cnameFlattening = true diff --git a/docs/content/reference/static-configuration/file.yaml b/docs/content/reference/static-configuration/file.yaml index 4410e29eb..d822979c9 100644 --- a/docs/content/reference/static-configuration/file.yaml +++ b/docs/content/reference/static-configuration/file.yaml @@ -397,68 +397,29 @@ accessLog: bufferingSize: 42 tracing: serviceName: foobar - spanNameLimit: 42 - jaeger: - samplingServerURL: foobar - samplingType: foobar - samplingParam: 42 - localAgentHostPort: foobar - gen128Bit: true - propagation: foobar - traceContextHeaderName: foobar - disableAttemptReconnecting: true - collector: + sampleRate: 42 + headers: + header1: foobar + header2: foobar + globalAttributes: + attr1: foobar + attr2: foobar + otlp: + grpc: endpoint: foobar - user: foobar - password: foobar - zipkin: - httpEndpoint: foobar - sameSpan: true - id128Bit: true - sampleRate: 42 - datadog: - localAgentHostPort: foobar - localAgentSocket: foobar - globalTags: - tag1: foobar - tag2: foobar - debug: true - prioritySampling: true - traceIDHeaderName: foobar - parentIDHeaderName: foobar - samplingPriorityHeaderName: foobar - bagagePrefixHeaderName: foobar - instana: - localAgentHost: foobar - localAgentPort: 42 - logLevel: foobar - enableAutoProfile: true - haystack: - localAgentHost: foobar - localAgentPort: 42 - globalTag: foobar - traceIDHeaderName: foobar - parentIDHeaderName: foobar - spanIDHeaderName: foobar - baggagePrefixHeaderName: foobar - elastic: - serverURL: foobar - secretToken: foobar - serviceEnvironment: foobar - openTelemetry: - address: foobar - headers: - name0: foobar - name1: foobar - insecure: true - path: foobar - tls: - ca: foobar - caOptional: true - cert: foobar - key: foobar - insecureSkipVerify: true - grpc: {} + insecure: true + tls: + ca: foobar + cert: foobar + key: foobar + insecureSkipVerify: true + http: + endpoint: foobar + tls: + ca: foobar + cert: foobar + key: foobar + insecureSkipVerify: true hostResolver: cnameFlattening: true resolvConfig: foobar diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 01cd88a98..6ba875a3f 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -153,19 +153,9 @@ nav: - 'Access Logs': 'observability/access-logs.md' - 'Metrics': - 'Overview': 'observability/metrics/overview.md' - - 'Datadog': 'observability/metrics/datadog.md' - - 'InfluxDB2': 'observability/metrics/influxdb2.md' - 'OpenTelemetry': 'observability/metrics/opentelemetry.md' - - 'Prometheus': 'observability/metrics/prometheus.md' - - 'StatsD': 'observability/metrics/statsd.md' - 'Tracing': - 'Overview': 'observability/tracing/overview.md' - - 'Jaeger': 'observability/tracing/jaeger.md' - - 'Zipkin': 'observability/tracing/zipkin.md' - - 'Datadog': 'observability/tracing/datadog.md' - - 'Instana': 'observability/tracing/instana.md' - - 'Haystack': 'observability/tracing/haystack.md' - - 'Elastic': 'observability/tracing/elastic.md' - 'OpenTelemetry': 'observability/tracing/opentelemetry.md' - 'User Guides': - 'Kubernetes and Let''s Encrypt': 'user-guides/crd-acme/index.md' diff --git a/go.mod b/go.mod index f0a5faf49..25d529a2d 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,6 @@ go 1.21 require ( github.com/BurntSushi/toml v1.3.2 - github.com/ExpediaDotCom/haystack-client-go v0.0.0-20190315171017-e7edbdf53a61 github.com/Masterminds/sprig/v3 v3.2.3 github.com/abbot/go-http-auth v0.0.0-00010101000000-000000000000 github.com/andybalholm/brotli v1.0.6 @@ -36,7 +35,6 @@ require ( github.com/http-wasm/http-wasm-host-go v0.5.2 github.com/influxdata/influxdb-client-go/v2 v2.7.0 github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d - github.com/instana/go-sensor v1.38.3 github.com/klauspost/compress v1.17.1 github.com/kvtools/consul v1.0.2 github.com/kvtools/etcdv3 v1.0.2 @@ -49,54 +47,46 @@ require ( github.com/mitchellh/hashstructure v1.0.0 github.com/mitchellh/mapstructure v1.5.0 github.com/natefinch/lumberjack v0.0.0-20201021141957-47ffae23317c - github.com/opentracing/opentracing-go v1.2.0 - github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5 - github.com/openzipkin/zipkin-go v0.2.2 github.com/patrickmn/go-cache v2.1.0+incompatible github.com/pires/go-proxyproto v0.6.1 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 github.com/prometheus/client_golang v1.14.0 github.com/prometheus/client_model v0.3.0 github.com/quic-go/quic-go v0.40.1 - github.com/rs/zerolog v1.28.0 + github.com/rs/zerolog v1.29.0 github.com/sirupsen/logrus v1.9.3 github.com/spiffe/go-spiffe/v2 v2.1.1 github.com/stretchr/testify v1.8.4 github.com/stvp/go-udp-testing v0.0.0-20191102171040-06b61409b154 github.com/tailscale/tscert v0.0.0-20220316030059-54bbcb9f74e2 github.com/tetratelabs/wazero v1.5.0 + github.com/tidwall/gjson v1.17.0 github.com/traefik/grpc-web v0.16.0 github.com/traefik/paerser v0.2.0 github.com/traefik/yaegi v0.15.1 - github.com/uber/jaeger-client-go v2.30.0+incompatible - github.com/uber/jaeger-lib v2.2.0+incompatible github.com/unrolled/render v1.0.2 github.com/unrolled/secure v1.0.9 github.com/vdemeester/shakers v0.1.0 github.com/vulcand/oxy/v2 v2.0.0-20230427132221-be5cf38f3c1c github.com/vulcand/predicate v1.2.0 - go.elastic.co/apm v1.13.1 - go.elastic.co/apm/module/apmot v1.13.1 go.opentelemetry.io/collector/pdata v0.66.0 - go.opentelemetry.io/otel v1.19.0 - go.opentelemetry.io/otel/bridge/opentracing v1.19.0 - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.42.0 - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.42.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 - go.opentelemetry.io/otel/metric v1.19.0 - go.opentelemetry.io/otel/sdk v1.19.0 - go.opentelemetry.io/otel/sdk/metric v1.19.0 - go.opentelemetry.io/otel/trace v1.19.0 + go.opentelemetry.io/otel v1.21.0 + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0 + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.44.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0 + go.opentelemetry.io/otel/metric v1.21.0 + go.opentelemetry.io/otel/sdk v1.21.0 + go.opentelemetry.io/otel/sdk/metric v1.21.0 + go.opentelemetry.io/otel/trace v1.21.0 golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 golang.org/x/mod v0.12.0 golang.org/x/net v0.17.0 golang.org/x/text v0.13.0 golang.org/x/time v0.3.0 golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 - google.golang.org/grpc v1.58.3 - gopkg.in/DataDog/dd-trace-go.v1 v1.56.1 + google.golang.org/grpc v1.59.0 gopkg.in/yaml.v3 v3.0.1 k8s.io/api v0.26.3 k8s.io/apiextensions-apiserver v0.26.3 @@ -129,13 +119,6 @@ require ( github.com/Azure/go-autorest/logger v0.2.1 // indirect github.com/Azure/go-autorest/tracing v0.6.0 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 // indirect - github.com/DataDog/appsec-internal-go v1.0.0 // indirect - github.com/DataDog/datadog-agent/pkg/obfuscate v0.48.0 // indirect - github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.48.0-devel.0.20230725154044-2549ba9058df // indirect - github.com/DataDog/datadog-go/v5 v5.3.0 // indirect - github.com/DataDog/go-libddwaf v1.5.0 // indirect - github.com/DataDog/go-tuf v1.0.2-0.5.2 // indirect - github.com/DataDog/sketches-go v1.4.2 // indirect github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver/v3 v3.2.0 // indirect @@ -148,7 +131,6 @@ require ( github.com/aliyun/alibaba-cloud-sdk-go v1.61.1755 // indirect github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect github.com/armon/go-metrics v0.4.1 // indirect - github.com/armon/go-radix v1.0.0 // indirect github.com/aws/aws-sdk-go-v2 v1.20.3 // indirect github.com/aws/aws-sdk-go-v2/config v1.18.28 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.13.27 // indirect @@ -190,26 +172,23 @@ require ( github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c // indirect github.com/docker/go-metrics v0.0.1 // indirect github.com/docker/go-units v0.4.0 // indirect - github.com/dustin/go-humanize v1.0.1 // indirect - github.com/ebitengine/purego v0.5.0-alpha.1 // indirect - github.com/elastic/go-licenser v0.3.1 // indirect - github.com/elastic/go-sysinfo v1.1.1 // indirect - github.com/elastic/go-windows v1.0.0 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/evanphx/json-patch v4.12.0+incompatible // indirect github.com/exoscale/egoscale v0.100.1 // indirect github.com/fatih/color v1.15.0 // indirect github.com/fvbommel/sortorder v1.0.1 // indirect github.com/ghodss/yaml v1.0.0 // indirect + github.com/gin-gonic/gin v1.7.7 // indirect github.com/go-errors/errors v1.0.1 // indirect github.com/go-jose/go-jose/v3 v3.0.0 // indirect github.com/go-logfmt/logfmt v0.5.1 // indirect - github.com/go-logr/logr v1.2.4 // indirect + github.com/go-logr/logr v1.3.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect github.com/go-openapi/jsonreference v0.20.0 // indirect github.com/go-openapi/swag v0.19.14 // indirect github.com/go-resty/resty/v2 v2.7.0 // indirect + github.com/go-sql-driver/mysql v1.6.0 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/go-zookeeper/zk v1.0.3 // indirect github.com/gofrs/flock v0.8.0 // indirect @@ -219,7 +198,7 @@ require ( github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/mock v1.6.0 // indirect github.com/google/gnostic v0.5.7-v3refs // indirect - github.com/google/go-cmp v0.5.9 // indirect + github.com/google/go-cmp v0.6.0 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b // indirect @@ -248,9 +227,7 @@ require ( github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 // indirect github.com/infobloxopen/infoblox-go-client v1.1.1 // indirect github.com/jaguilar/vt100 v0.0.0-20150826170717-2703a27b14ea // indirect - github.com/jcchavezs/porto v0.1.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect - github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 // indirect github.com/jonboulle/clockwork v0.2.2 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect @@ -264,7 +241,6 @@ require ( github.com/liquidweb/go-lwApi v0.0.5 // indirect github.com/liquidweb/liquidweb-cli v0.6.9 // indirect github.com/liquidweb/liquidweb-go v1.6.3 // indirect - github.com/looplab/fsm v0.1.0 // indirect github.com/magiconair/properties v1.8.6 // indirect github.com/mailgun/minheap v0.0.0-20170619185613-3dbe6c6bf55f // indirect github.com/mailgun/multibuf v0.1.2 // indirect @@ -300,15 +276,14 @@ require ( github.com/nrdcg/porkbun v0.2.0 // indirect github.com/nzdjb/go-metaname v1.0.0 // indirect github.com/onsi/ginkgo v1.16.5 // indirect - github.com/onsi/ginkgo/v2 v2.9.5 // indirect + github.com/onsi/ginkgo/v2 v2.11.0 // indirect + github.com/onsi/gomega v1.27.10 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.0.2 // indirect + github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b // indirect github.com/opencontainers/runc v1.1.5 // indirect - github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492 // indirect + github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/oracle/oci-go-sdk v24.3.0+incompatible // indirect - github.com/outcaste-io/ristretto v0.2.3 // indirect github.com/ovh/go-ovh v1.4.1 // indirect - github.com/philhofer/fwd v1.1.2 // indirect github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pquerna/otp v1.4.0 // indirect @@ -323,22 +298,21 @@ require ( github.com/sacloud/iaas-api-go v1.11.1 // indirect github.com/sacloud/packages-go v0.0.9 // indirect github.com/sanathkr/go-yaml v0.0.0-20170819195128-ed9d249f429b // indirect - github.com/santhosh-tekuri/jsonschema v1.2.4 // indirect github.com/scaleway/scaleway-sdk-go v1.0.0-beta.17 // indirect - github.com/secure-systems-lab/go-securesystemslib v0.7.0 // indirect github.com/shopspring/decimal v1.2.0 // indirect github.com/simplesurance/bunny-go v0.0.0-20221115111006-e11d9dc91f04 // indirect github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9 // indirect github.com/softlayer/softlayer-go v1.1.2 // indirect github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e // indirect - github.com/spf13/cast v1.3.1 // indirect + github.com/spf13/cast v1.5.0 // indirect github.com/spf13/cobra v1.6.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/objx v0.5.1 // indirect github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.490 // indirect github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.490 // indirect github.com/theupdateframework/notary v0.6.1 // indirect - github.com/tinylib/msgp v1.1.8 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect github.com/tonistiigi/fsutil v0.0.0-20201103201449-0834f99b7b85 // indirect github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea // indirect github.com/transip/gotransip/v6 v6.20.0 // indirect @@ -351,42 +325,34 @@ require ( github.com/yandex-cloud/go-genproto v0.0.0-20220805142335-27b56ddae16f // indirect github.com/yandex-cloud/go-sdk v0.0.0-20220805164847-cf028e604997 // indirect github.com/zeebo/errs v1.2.2 // indirect - go.elastic.co/apm/module/apmhttp v1.13.1 // indirect - go.elastic.co/fastjson v1.1.0 // indirect go.etcd.io/etcd/api/v3 v3.5.5 // indirect go.etcd.io/etcd/client/pkg/v3 v3.5.5 // indirect go.etcd.io/etcd/client/v3 v3.5.5 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.42.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/mock v0.3.0 // indirect go.uber.org/multierr v1.8.0 // indirect go.uber.org/ratelimit v0.2.0 // indirect go.uber.org/zap v1.21.0 // indirect - go4.org/intern v0.0.0-20230525184215-6c62f75575cb // indirect - go4.org/unsafe/assume-no-moving-gc v0.0.0-20230525183740-e7c30c78aeb2 // indirect golang.org/x/crypto v0.14.0 // indirect - golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect - golang.org/x/oauth2 v0.10.0 // indirect + golang.org/x/oauth2 v0.11.0 // indirect golang.org/x/sync v0.3.0 // indirect - golang.org/x/sys v0.13.0 // indirect + golang.org/x/sys v0.14.0 // indirect golang.org/x/term v0.13.0 // indirect - golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/api v0.128.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect + google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect google.golang.org/protobuf v1.31.0 // indirect + gopkg.in/h2non/gock.v1 v1.0.16 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/ns1/ns1-go.v2 v2.7.6 // indirect gopkg.in/square/go-jose.v2 v2.5.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - howett.net/plist v0.0.0-20181124034731-591f970eefbb // indirect - inet.af/netaddr v0.0.0-20230525184311-b8eac61e914a // indirect - k8s.io/klog/v2 v2.80.1 // indirect + k8s.io/klog/v2 v2.90.1 // indirect k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect nhooyr.io/websocket v1.8.7 // indirect sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect diff --git a/go.sum b/go.sum index 9780e2eb5..e51ba4439 100644 --- a/go.sum +++ b/go.sum @@ -118,25 +118,7 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/DataDog/appsec-internal-go v1.0.0 h1:2u5IkF4DBj3KVeQn5Vg2vjPUtt513zxEYglcqnd500U= -github.com/DataDog/appsec-internal-go v1.0.0/go.mod h1:+Y+4klVWKPOnZx6XESG7QHydOaUGEXyH2j/vSg9JiNM= -github.com/DataDog/datadog-agent/pkg/obfuscate v0.48.0 h1:bUMSNsw1iofWiju9yc1f+kBd33E3hMJtq9GuU602Iy8= -github.com/DataDog/datadog-agent/pkg/obfuscate v0.48.0/go.mod h1:HzySONXnAgSmIQfL6gOv9hWprKJkx8CicuXuUbmgWfo= -github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.48.0-devel.0.20230725154044-2549ba9058df h1:PbzrhHhs2+RRdKKti7JBSM8ATIeiji2T2cVt/d8GT8k= -github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.48.0-devel.0.20230725154044-2549ba9058df/go.mod h1:5Q39ZOIOwZMnFyRadp+5gH1bFdjmb+Pgxe+j5XOwaTg= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= -github.com/DataDog/datadog-go/v5 v5.3.0 h1:2q2qjFOb3RwAZNU+ez27ZVDwErJv5/VpbBPprz7Z+s8= -github.com/DataDog/datadog-go/v5 v5.3.0/go.mod h1:XRDJk1pTc00gm+ZDiBKsjh7oOOtJfYfglVCmFb8C2+Q= -github.com/DataDog/go-libddwaf v1.5.0 h1:lrHP3VrEriy1M5uQuaOcKphf5GU40mBhihMAp6Ik55c= -github.com/DataDog/go-libddwaf v1.5.0/go.mod h1:Fpnmoc2k53h6desQrH1P0/gR52CUzkLNFugE5zWwUBQ= -github.com/DataDog/go-tuf v1.0.2-0.5.2 h1:EeZr937eKAWPxJ26IykAdWA4A0jQXJgkhUjqEI/w7+I= -github.com/DataDog/go-tuf v1.0.2-0.5.2/go.mod h1:zBcq6f654iVqmkk8n2Cx81E1JnNTMOAx1UEO/wZR+P0= -github.com/DataDog/gostackparse v0.7.0 h1:i7dLkXHvYzHV308hnkvVGDL3BR4FWl7IsXNPz/IGQh4= -github.com/DataDog/gostackparse v0.7.0/go.mod h1:lTfqcJKqS9KnXQGnyQMCugq3u1FP6UZMfWR0aitKFMM= -github.com/DataDog/sketches-go v1.4.2 h1:gppNudE9d19cQ98RYABOetxIhpTCl4m7CnbRZjvVA/o= -github.com/DataDog/sketches-go v1.4.2/go.mod h1:xJIXldczJyyjnbDop7ZZcLxJdV3+7Kra7H1KMgpgkLk= -github.com/ExpediaDotCom/haystack-client-go v0.0.0-20190315171017-e7edbdf53a61 h1:1NIUJ+MAMpqDr4LWIfNsoJR+G7zg/8GZVwuRkmJxtTc= -github.com/ExpediaDotCom/haystack-client-go v0.0.0-20190315171017-e7edbdf53a61/go.mod h1:62qWSDaEI0BLykU+zQza5CAKgW0lOy9oBSz3/DvYz4w= github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0= github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM= @@ -157,7 +139,6 @@ github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugX github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= -github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= @@ -188,8 +169,6 @@ github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdko github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= -github.com/Shopify/sarama v1.38.1 h1:lqqPUPQZ7zPqYlWpTh+LQ9bhYNu2xJL6k1SJN4WVe2A= -github.com/Shopify/sarama v1.38.1/go.mod h1:iwv9a67Ha8VNa+TifujYoWGxWnu2kNVAQdSdZ4X2o5g= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= @@ -227,7 +206,6 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmV github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= @@ -308,8 +286,6 @@ github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0Bsq github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= github.com/bugsnag/panicwrap v1.2.0 h1:OzrKrRvXis8qEvOkfcxNcYbOd2O7xXS2nnKMEMABFQA= github.com/bugsnag/panicwrap v1.2.0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= -github.com/bytedance/sonic v1.10.0 h1:qtNZduETEIWJVIyDl01BeNxur2rW9OwTQ/yBqFRkKEk= -github.com/bytedance/sonic v1.10.0/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= github.com/c-bata/go-prompt v0.2.5/go.mod h1:vFnjEGDIIA/Lib7giyE4E9c50Lvl8j0S+7FVlAwDAVw= github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= @@ -330,10 +306,6 @@ github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= -github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= -github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= -github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo= -github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -370,7 +342,6 @@ github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20160425231609-f8ad88b59a58/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/compose-spec/compose-go v1.0.2/go.mod h1:gCIA3No0j5nNszz2X0yd/mkigTIWcOgHiPa9guWvoec= github.com/compose-spec/compose-go v1.0.3 h1:yvut1x9H4TUMptNA4mZ63VGVtDNX1OKy2TZCi6yFw8Q= @@ -546,8 +517,6 @@ github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE= github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= -github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= @@ -617,28 +586,12 @@ github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZ github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= -github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/dvyukov/go-fuzz v0.0.0-20210103155950-6a8e9d1f2415/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= -github.com/eapache/go-resiliency v1.4.0 h1:3OK9bWpPk5q6pbFAaYSEwD9CLUSHG8bnZuqX2yMt3B0= -github.com/eapache/go-resiliency v1.4.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6iZYSs1ZI+iQho= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= -github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 h1:Oy0F4ALJ04o5Qqpdz8XLIpNA3WM/iSIXqxtqo7UGVws= -github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3/go.mod h1:YvSRo5mw33fLEx1+DlK6L2VV43tJt5Eyel9n9XBcR+0= -github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/ebitengine/purego v0.5.0-alpha.1 h1:0gVgWGb8GjKYs7cufvfNSleJAD00m2xWC26FMwOjNrw= -github.com/ebitengine/purego v0.5.0-alpha.1/go.mod h1:ah1In8AOtksoNK6yk5z1HTJeUkC1Ez4Wk2idgGslMwQ= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 h1:clC1lXBpe2kTj2VHdaIu9ajZQe4kcEY9j0NsnDDBZ3o= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= -github.com/elastic/go-licenser v0.3.1 h1:RmRukU/JUmts+rpexAw0Fvt2ly7VVu6mw8z4HrEzObU= -github.com/elastic/go-licenser v0.3.1/go.mod h1:D8eNQk70FOCVBl3smCGQt/lv7meBeQno2eI1S5apiHQ= -github.com/elastic/go-sysinfo v1.1.1 h1:ZVlaLDyhVkDfjwPGU55CQRCRolNpc7P0BbyhhQZQmMI= -github.com/elastic/go-sysinfo v1.1.1/go.mod h1:i1ZYdU10oLNfRzq4vq62BEwD2fH8KaWh6eh0ikPT9F0= -github.com/elastic/go-windows v1.0.0 h1:qLURgZFkkrYyTTkvYpsZIgf83AUsdIHfvlJaqaZ7aSY= -github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU= github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/elazarl/goproxy v0.0.0-20191011121108-aa519ddbe484/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= @@ -682,6 +635,8 @@ github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoD github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= +github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= +github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= @@ -703,8 +658,8 @@ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= -github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= -github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= +github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs= +github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/go-acme/lego/v4 v4.14.0 h1:/skZoRHgVh0d2RK7l1g3Ch8HqeqP9LB8ZEjLdGEpcDE= github.com/go-acme/lego/v4 v4.14.0/go.mod h1:zjmvNCDLGz7GrC1OqdVpVmZFKSRabEDtWbdzmcpBsGo= @@ -734,8 +689,8 @@ github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTg github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v0.4.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= @@ -770,8 +725,8 @@ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91 github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= github.com/go-playground/validator/v10 v10.9.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= -github.com/go-playground/validator/v10 v10.15.1 h1:BSe8uhN+xQ4r5guV/ywQI4gO59C2raYcGffYWZEjZzM= -github.com/go-playground/validator/v10 v10.15.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= +github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY= github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I= github.com/go-sql-driver/mysql v1.3.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= @@ -801,8 +756,6 @@ github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/E github.com/gobwas/ws v1.2.1 h1:F2aeBZrm2NDsc7vbovKrWSogd4wvfAxg0FQ89/iqOTk= github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= github.com/goccy/go-json v0.7.8/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= -github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= @@ -814,9 +767,8 @@ github.com/gofrs/flock v0.7.3/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14j github.com/gofrs/flock v0.8.0 h1:MSdYClljsF3PbENUUEx85nkWfJSGfzYI9yEBZOJz6CY= github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid v3.3.0+incompatible h1:8K4tyRfvU1CYPgJsveYFQMhpFd/wXNM7iK6rR7UHz84= github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= -github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU= github.com/gogo/googleapis v1.3.0/go.mod h1:d+q1s/xVJxZGKWwC/6UfPIF33J+G1Tq4GYv9Y+Tg/EU= @@ -839,8 +791,8 @@ github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOW github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= -github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= +github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= +github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -880,8 +832,6 @@ github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= -github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= github.com/google/btree v0.0.0-20180124185431-e89373fe6b4a/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -907,8 +857,8 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-containerregistry v0.0.0-20191015185424-71da34e4d9b3/go.mod h1:ZXFeSndFcK4vB1NR4voH1Zm38K7ViUNiYtfIBDxrwf0= github.com/google/go-github/v28 v28.1.1 h1:kORf5ekX5qwXO2mGzXXOjMe/g6ap8ahVe0sBEulhSxo= github.com/google/go-github/v28 v28.1.1/go.mod h1:bsqJWQX05omyWVmc00nEUql9mhQyv38lDZ8kPZcQVoM= @@ -1068,9 +1018,8 @@ github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uG github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM= -github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= github.com/hashicorp/hcl/v2 v2.8.2/go.mod h1:bQTN5mpo+jewjJgh8jr0JUguIi7qPHUF6yIfAEN3jqY= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= @@ -1114,32 +1063,15 @@ github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 h1:W9WBk7 github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= github.com/infobloxopen/infoblox-go-client v1.1.1 h1:728A6LbLjptj/7kZjHyIxQnm768PWHfGFm0HH8FnbtU= github.com/infobloxopen/infoblox-go-client v1.1.1/go.mod h1:BXiw7S2b9qJoM8MS40vfgCNB2NLHGusk1DtO16BD9zI= -github.com/instana/go-sensor v1.38.3 h1:/PdHEDveLmUCvK+O6REvSv8kKljX8vaj9JMjMeCHAWk= -github.com/instana/go-sensor v1.38.3/go.mod h1:E42MelHWFz11qqaLwvgt0j98v2s2O/bq22UDkGaG0Gg= -github.com/instana/testify v1.6.2-0.20200721153833-94b1851f4d65 h1:T25FL3WEzgmKB0m6XCJNZ65nw09/QIp3T1yXr487D+A= -github.com/instana/testify v1.6.2-0.20200721153833-94b1851f4d65/go.mod h1:nYhEREG/B7HUY7P+LKOrqy53TpIqmJ9JyUShcaEKtGw= github.com/ishidawataru/sctp v0.0.0-20191218070446-00ab2ac2db07/go.mod h1:co9pwDoBCm1kGxawmb4sPq0cSIOOWNPT4KnHotMP1Zg= github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA= github.com/jarcoal/httpmock v1.0.8/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= github.com/jarcoal/httpmock v1.3.0 h1:2RJ8GP0IIaWwcC9Fp2BmVi8Kog3v2Hn7VXM3fTd+nuc= github.com/jarcoal/httpmock v1.3.0/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg= -github.com/jcchavezs/porto v0.1.0 h1:Xmxxn25zQMmgE7/yHYmh19KcItG81hIwfbEEFnd6w/Q= -github.com/jcchavezs/porto v0.1.0/go.mod h1:fESH0gzDHiutHRdX2hv27ojnOVFco37hg1W6E9EZF4A= -github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= -github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= -github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= -github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= -github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg= -github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= -github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8= -github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= -github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= -github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jinzhu/gorm v1.9.2/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo= +github.com/jinzhu/gorm v1.9.11 h1:gaHGvE+UnWGlbWG4Y3FUwY1EcZ5n6S9WtqBA/uySMLE= github.com/jinzhu/gorm v1.9.11/go.mod h1:bu/pK8szGZ2puuErfU0RwyeNdsf3e6nCX/noXaVxkfw= -github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o= -github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs= github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= @@ -1155,8 +1087,6 @@ github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGw github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jmhodges/clock v0.0.0-20160418191101-880ee4c33548/go.mod h1:hGT6jSUVzF6no3QaDSMLGLEHtHSBSefs+MgcDWnmhmo= github.com/jmoiron/sqlx v0.0.0-20180124204410-05cef0741ade/go.mod h1:IiEW3SEiiErVyFdH8NTuWjSifiEQKUoyK3LNqr2kCHU= -github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4= -github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= @@ -1198,8 +1128,6 @@ github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYs github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.17.1 h1:NE3C767s2ak2bweCZo3+rdP4U/HoyVXLv/X9f2gPS5g= github.com/klauspost/compress v1.17.1/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= -github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= -github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b h1:udzkj9S/zlT5X367kqJis0QP7YMxobob6zhzq6Yre00= github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b/go.mod h1:pcaDhQK0/NJZEvtCO0qQPPropqV0sJOJ6YW7X+9kRwM= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -1270,8 +1198,6 @@ github.com/liquidweb/liquidweb-cli v0.6.9/go.mod h1:cE1uvQ+x24NGUL75D0QagOFCG8Wd github.com/liquidweb/liquidweb-go v1.6.3 h1:NVHvcnX3eb3BltiIoA+gLYn15nOpkYkdizOEYGSKrk4= github.com/liquidweb/liquidweb-go v1.6.3/go.mod h1:SuXXp+thr28LnjEw18AYtWwIbWMHSUiajPQs8T9c/Rc= github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= -github.com/looplab/fsm v0.1.0 h1:Qte7Zdn/5hBNbXzP7yxVU4OIFHWXBovyTT2LaBTyC20= -github.com/looplab/fsm v0.1.0/go.mod h1:m2VaOfDHxqXBBMgc26m6yUOwkFn8H2AlJDE+jd/uafI= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= @@ -1469,8 +1395,8 @@ github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= -github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k= +github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= +github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= @@ -1484,8 +1410,8 @@ github.com/onsi/gomega v1.14.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+t github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= -github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= -github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= +github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= +github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= @@ -1495,8 +1421,8 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= -github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b h1:YWuSjZCQAPM8UUBLkYUk1e+rZcvWHJmFb6i6rM44Xs8= +github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v1.0.0-rc10/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= @@ -1521,7 +1447,6 @@ github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3 github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= github.com/opencontainers/selinux v1.10.0 h1:rAiKF8hTcgLI3w0DHm6i0ylVVcOrlgR1kK99DRLDhyU= github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= -github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492 h1:lM6RxxfUMrYL/f8bWEUqdXrANWtrL7Nndbm9iFN0DlU= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing-contrib/go-stdlib v1.0.0/go.mod h1:qtI1ogk+2JhVPIXVc6q+NHziSmy2W5GbdQZFUHADCBU= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= @@ -1529,16 +1454,12 @@ github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFSt github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= -github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5 h1:ZCnq+JUrvXcDVhX/xRolRBZifmabN1HcS1wrPSvxhrU= github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= -github.com/openzipkin/zipkin-go v0.2.2 h1:nY8Hti+WKaP0cRsSeQ026wU03QsM762XBeCXBb9NAWI= github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/oracle/oci-go-sdk v24.3.0+incompatible h1:x4mcfb4agelf1O4/1/auGlZ1lr97jXRSSN5MxTgG/zU= github.com/oracle/oci-go-sdk v24.3.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= -github.com/outcaste-io/ristretto v0.2.3 h1:AK4zt/fJ76kjlYObOeNwh4T3asEuaCmp26pOvUOL9w0= -github.com/outcaste-io/ristretto v0.2.3/go.mod h1:W8HywhmtlopSB1jeMg3JtdIhf+DYkLAr0VN/s4+MHac= github.com/ovh/go-ovh v1.4.1 h1:VBGa5wMyQtTP7Zb+w97zRCh9sLtM/2YKRyy+MEJmWaM= github.com/ovh/go-ovh v1.4.1/go.mod h1:6bL6pPyUT7tBfI0pqOegJgRjgjuO+mOo+MyXd1EEC0M= github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= @@ -1552,17 +1473,10 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9 github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0= -github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= -github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw= -github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= -github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= -github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ= -github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pires/go-proxyproto v0.6.1 h1:EBupykFmo22SDjv4fQVQd2J9NOoLPmyZA/15ldOGkPw= github.com/pires/go-proxyproto v0.6.1/go.mod h1:Odh9VFOZJCf9G8cLW5o435Xf1J95Jw9Gw5rnCjcwzAY= github.com/pivotal/image-relocation v0.0.0-20191111101224-e94aff6df06c/go.mod h1:/JNbQwGylYm3AQh8q+MBF8e/h0W1Jy20JGTvozuXYTE= @@ -1626,7 +1540,6 @@ github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJ github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -1649,26 +1562,22 @@ github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58 github.com/quic-go/quic-go v0.40.1 h1:X3AGzUNFs0jVuO3esAGnTfvdgvL4fq655WaOi1snv1Q= github.com/quic-go/quic-go v0.40.1/go.mod h1:PeN7kuVJ4xZbxSv/4OX6S1USOX8MJvydwpTx31vx60c= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= -github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/redis/go-redis/v9 v9.2.1 h1:WlYJg71ODF0dVspZZCpYmoF1+U1Jjk9Rwd7pq6QmlCg= github.com/redis/go-redis/v9 v9.2.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= -github.com/richardartoul/molecule v1.0.1-0.20221107223329-32cfee06a052 h1:Qp27Idfgi6ACvFQat5+VJvlYToylpM/hcyLBI3WaKPA= -github.com/richardartoul/molecule v1.0.1-0.20221107223329-32cfee06a052/go.mod h1:uvX/8buq8uVeiZiFht+0lqSLBHF+uGV8BrTv8W/SIwk= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= 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.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= -github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= 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.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.28.0 h1:MirSo27VyNi7RJYP3078AA1+Cyzd2GB66qy3aUHvsWY= -github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= +github.com/rs/zerolog v1.29.0 h1:Zes4hju04hjbvkVkOhdl2HpZa+0PmVwigmo8XoORE5w= +github.com/rs/zerolog v1.29.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -1685,8 +1594,6 @@ github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiB github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/sanathkr/go-yaml v0.0.0-20170819195128-ed9d249f429b h1:jUK33OXuZP/l6babJtnLo1qsGvq6G9so9KMflGAm4YA= github.com/sanathkr/go-yaml v0.0.0-20170819195128-ed9d249f429b/go.mod h1:8458kAagoME2+LN5//WxE71ysZ3B7r22fdgb7qVmXSY= -github.com/santhosh-tekuri/jsonschema v1.2.4 h1:hNhW8e7t+H1vgY+1QeEQpveR6D4+OwKPXCfD2aieJis= -github.com/santhosh-tekuri/jsonschema v1.2.4/go.mod h1:TEAUOeZSmIxTTuHatJzrvARHiuO9LYd+cIxzgEHCQI4= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/scaleway/scaleway-sdk-go v1.0.0-beta.17 h1:1WuWJu7/e8SqK+uQl7lfk/N/oMZTL2NE/TJsNKRNMc4= github.com/scaleway/scaleway-sdk-go v1.0.0-beta.17/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg= @@ -1694,8 +1601,6 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUt github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= -github.com/secure-systems-lab/go-securesystemslib v0.7.0 h1:OwvJ5jQf9LnIAS83waAjPbcMsODrTQUpJ02eNLUoxBg= -github.com/secure-systems-lab/go-securesystemslib v0.7.0/go.mod h1:/2gYnlnHVQ6xeGtfIqFy7Do03K4cdCY0A/GlJLDKLHI= github.com/segmentio/fasthash v1.0.3 h1:EI9+KE1EwvMLBWwjpRDc+fEM+prwxDYbslddQGtrmhM= github.com/segmentio/fasthash v1.0.3/go.mod h1:waKX8l2N8yckOgmSsXJi7x1ZfdKZ4x7KRMzBtS3oedY= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= @@ -1733,16 +1638,15 @@ github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e/go.mod h1:fKZCUVd github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= -github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.4.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= +github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= @@ -1817,8 +1721,12 @@ github.com/tetratelabs/wazero v1.5.0 h1:Yz3fZHivfDiZFUXnWMPUoiW7s8tC1sjdBtlJn08q github.com/tetratelabs/wazero v1.5.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A= github.com/theupdateframework/notary v0.6.1 h1:7wshjstgS9x9F5LuB1L5mBI2xNMObWqjz+cjWoom6l0= github.com/theupdateframework/notary v0.6.1/go.mod h1:MOfgIfmox8s7/7fduvB2xyPPMJCrjRLRizA8OFwpnKY= -github.com/tinylib/msgp v1.1.8 h1:FCXC1xanKO4I8plpHGH2P7koL/RzZs12l/+r7vakfm0= -github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw= +github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM= +github.com/tidwall/gjson v1.17.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tonistiigi/fsutil v0.0.0-20201103201449-0834f99b7b85 h1:014iQD8i8EabPWK2XgUuOTxg5s2nhfDmq6GupskfUO8= @@ -1836,12 +1744,7 @@ github.com/traefik/yaegi v0.15.1/go.mod h1:AVRxhaI2G+nUsaM1zyktzwXn69G3t/AuTDrCi github.com/transip/gotransip/v6 v6.20.0 h1:AuvwyOZ51f2brzMbTqlRy/wmaM3kF7Vx5Wds8xcDflY= github.com/transip/gotransip/v6 v6.20.0/go.mod h1:nzv9eN2tdsUrm5nG5ZX6AugYIU4qgsMwIn2c0EZLk8c= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= -github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= -github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/uber/jaeger-client-go v2.25.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= -github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o= -github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= -github.com/uber/jaeger-lib v2.2.0+incompatible h1:MxZXOiR2JuoANZ3J6DE/U0kSFv/eJ/GfSYVCjK7dyaw= github.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= @@ -1849,9 +1752,8 @@ github.com/ugorji/go v1.2.6 h1:tGiWC9HENWE2tqYycIqFTNorMmFRVhNwCpDOpWqnk8E= github.com/ugorji/go v1.2.6/go.mod h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn0= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/ugorji/go/codec v1.2.6 h1:7kbGefxLoDBuYXOms4yD7223OpNMMPNPZxXk5TvFcyQ= github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw= -github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= -github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/ultradns/ultradns-go-sdk v1.5.0-20230427130837-23c9b0c h1:mKnW6IGLw7uXu6DL6RitufZWcXS6hCnauXRUFof7rKM= github.com/ultradns/ultradns-go-sdk v1.5.0-20230427130837-23c9b0c/go.mod h1:F4UyVEmq4/m5lAmx+GccrxyRCXmnBjzUL09JLTQFp94= github.com/unrolled/render v1.0.2 h1:dGS3EmChQP3yOi1YeFNO/Dx+MbWZhdvhQJTXochM5bs= @@ -1927,14 +1829,6 @@ github.com/zmap/zcrypto v0.0.0-20190729165852-9051775e6a2e h1:mvOa4+/DXStR4ZXOks github.com/zmap/zcrypto v0.0.0-20190729165852-9051775e6a2e/go.mod h1:w7kd3qXHh8FNaczNjslXqvFQiv5mMWRXlL9klTUAHc8= github.com/zmap/zlint v0.0.0-20190806154020-fd021b4cfbeb h1:vxqkjztXSaPVDc8FQCdHTaejm2x747f6yPbnu1h2xkg= github.com/zmap/zlint v0.0.0-20190806154020-fd021b4cfbeb/go.mod h1:29UiAJNsiVdvTBFCJW8e3q6dcDbOoPkhMgttOSCIMMY= -go.elastic.co/apm v1.13.1 h1:ICIcUcQOImg/bve9mQVyLCvm1cSUZ1afdwK6ACnxczU= -go.elastic.co/apm v1.13.1/go.mod h1:dylGv2HKR0tiCV+wliJz1KHtDyuD8SPe69oV7VyK6WY= -go.elastic.co/apm/module/apmhttp v1.13.1 h1:g2id6+AY8NRSA6nzwPDSU1AmBiHyZeh/lJRBlXq2yfQ= -go.elastic.co/apm/module/apmhttp v1.13.1/go.mod h1:PmSy4HY0asQzoFpl+gna9n+ebfI43fPvo21sd22gquE= -go.elastic.co/apm/module/apmot v1.13.1 h1:4PCbjgVz0A/9a/wuiHu1en83TLgmBbK9fJwLgES8Rr8= -go.elastic.co/apm/module/apmot v1.13.1/go.mod h1:NnG6U6ahaixUHpjQioL0QvVtOxWjVn8Z09qJHSCsmqU= -go.elastic.co/fastjson v1.1.0 h1:3MrGBWWVIxe/xvsbpghtkFoPciPhOCmjsR/HfwEeQR4= -go.elastic.co/fastjson v1.1.0/go.mod h1:boNGISWMjQsUPy/t6yqt2/1Wx4YNPSe+mZjlyw9vKKI= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= @@ -1963,30 +1857,26 @@ 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 v0.66.0 h1:UdE5U6MsDNzuiWaXdjGx2lC3ElVqWmN/hiUE8vyvSuM= go.opentelemetry.io/collector/pdata v0.66.0/go.mod h1:pqyaznLzk21m+1KL6fwOsRryRELL+zNM0qiVSn0MbVc= -go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= -go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= -go.opentelemetry.io/otel/bridge/opentracing v1.19.0 h1:HCvsUi6uuhat/nAuxCl41A+OPxXXPxMNTRxKZx7hTW4= -go.opentelemetry.io/otel/bridge/opentracing v1.19.0/go.mod h1:n46h+7L/lcSuHhpqJQiUdb4eux19NNxTuWJ/ZMnIQMg= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.42.0 h1:ZtfnDL+tUrs1F0Pzfwbg2d59Gru9NCH3bgSHBM6LDwU= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.42.0/go.mod h1:hG4Fj/y8TR/tlEDREo8tWstl9fO9gcFkn4xrx0Io8xU= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.42.0 h1:NmnYCiR0qNufkldjVvyQfZTHSdzeHoZ41zggMsdMcLM= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.42.0/go.mod h1:UVAO61+umUsHLtYb8KXXRoHtxUkdOPkYidzW3gipRLQ= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.42.0 h1:wNMDy/LVGLj2h3p6zg4d0gypKfWKSWI14E1C4smOgl8= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.42.0/go.mod h1:YfbDdXAAkemWJK3H/DshvlrxqFB2rtW4rY6ky/3x/H0= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 h1:3d+S281UTjM+AbF31XSOYn1qXn3BgIdWl8HNEpx08Jk= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0/go.mod h1:0+KuTDyKL4gjKCF75pHOX4wuzYDUZYfAQdSu43o+Z2I= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU= -go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE= -go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= -go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o= -go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= -go.opentelemetry.io/otel/sdk/metric v1.19.0 h1:EJoTO5qysMsYCa+w4UghwFV/ptQgqSL/8Ni+hx+8i1k= -go.opentelemetry.io/otel/sdk/metric v1.19.0/go.mod h1:XjG0jQyFJrv2PbMvwND7LwCEhsJzCzV5210euduKcKY= -go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= -go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= +go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= +go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0 h1:jd0+5t/YynESZqsSyPz+7PAFdEop0dlN0+PkyHYo8oI= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0/go.mod h1:U707O40ee1FpQGyhvqnzmCJm1Wh6OX6GGBVn0E6Uyyk= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.44.0 h1:bflGWrfYyuulcdxf14V6n9+CoQcu5SAAdHmDPAJnlps= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.44.0/go.mod h1:qcTO4xHAxZLaLxPd60TdE88rxtItPHgHWqOhOGRr0as= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0/go.mod h1:zgBdWWAu7oEEMC06MMKc5NLbA/1YDXV1sMpSqEeLQLg= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 h1:tIqheXEFWAZ7O8A7m+J0aPTmpJN3YQ7qetUAdkkkKpk= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0/go.mod h1:nUeKExfxAQVbiVFn32YXpXZZHZ61Cc3s3Rn1pDBGAb0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0 h1:digkEZCJWobwBqMwC0cwCq8/wkkRy/OowZg5OArWZrM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0/go.mod h1:/OpE/y70qVkndM0TrxT4KBoN3RsFZP0QaofcfYrj76I= +go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= +go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= +go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= +go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= +go.opentelemetry.io/otel/sdk/metric v1.21.0 h1:smhI5oD714d6jHE6Tie36fPx4WDFIg+Y6RfAY4ICcR0= +go.opentelemetry.io/otel/sdk/metric v1.21.0/go.mod h1:FJ8RAsoPGv/wYMgBdUJXOm+6pzFY3YdljnXtv1SBE8Q= +go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= +go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= @@ -1994,14 +1884,13 @@ go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= -go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo= go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= @@ -2018,14 +1907,6 @@ go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= -go4.org/intern v0.0.0-20211027215823-ae77deb06f29/go.mod h1:cS2ma+47FKrLPdXFpr7CuxiTW3eyJbWew4qx0qtQWDA= -go4.org/intern v0.0.0-20230525184215-6c62f75575cb h1:ae7kzL5Cfdmcecbh22ll7lYP3iuUdnfnhiPcSaDgH/8= -go4.org/intern v0.0.0-20230525184215-6c62f75575cb/go.mod h1:Ycrt6raEcnF5FTsLiLKkhBTO6DPX3RCUCUVnks3gFJU= -go4.org/unsafe/assume-no-moving-gc v0.0.0-20211027215541-db492cf91b37/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E= -go4.org/unsafe/assume-no-moving-gc v0.0.0-20230525183740-e7c30c78aeb2 h1:WJhcL4p+YeDxmZWg141nRm7XC8IDmhz7lk5GpadO1Sg= -go4.org/unsafe/assume-no-moving-gc v0.0.0-20230525183740-e7c30c78aeb2/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E= -golang.org/x/arch v0.4.0 h1:A8WCeEWhLwPBKNbFi5Wv5UTCBx5zzubnXDlMOFAzFMc= -golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -2096,7 +1977,6 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= @@ -2111,7 +1991,6 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -2143,6 +2022,7 @@ golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191021144547-ec77196f6094/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -2182,7 +2062,6 @@ golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180724155351-3d292e4d0cdc/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -2200,8 +2079,8 @@ golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8= -golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= +golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU= +golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -2214,7 +2093,6 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -2258,7 +2136,6 @@ golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191025021431-6c3a3bfe00ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -2338,24 +2215,21 @@ golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.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-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -2370,7 +2244,6 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -2434,7 +2307,6 @@ golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjs golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -2457,15 +2329,12 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 h1:Vve/L0v7CXXuxUmaMGIEK/dEeq7uiqb5qBgQrZzIE7E= golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.8.2 h1:CCXrcPKiGGotvnN6jfUsKk4rRqm7q09/YbKb5xCEvtM= @@ -2560,12 +2429,12 @@ google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20211021150943-2b146023228c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 h1:Z0hjGZePRE0ZBWotvtrwxFNrNE9CUAGtplaDK5NNI/g= -google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98/go.mod h1:S7mY02OqCJTD0E1OiQy1F72PWFB4bZJ87cAtLPYgDR0= -google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 h1:FmF5cCW94Ij59cfpoLiwTgodWmm60eEV0CjlsVg2fuw= -google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= +google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d h1:VBu5YqKPv6XiJ199exd8Br+Aetz+o08F+PLMnwJQHAY= +google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= +google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d h1:DoPTO70H+bcDXcd39vOqb2viZxgqeBeSGtZ55yZU4/Q= +google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -2597,8 +2466,8 @@ google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9K google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ= -google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= +google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/grpc/examples v0.0.0-20201130180447-c456688b1860/go.mod h1:Ly7ZA/ARzg8fnPU9TyZIxoz33sEUuWX7txiqs8lPTgE= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -2616,8 +2485,6 @@ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/DataDog/dd-trace-go.v1 v1.56.1 h1:AUe/ZF7xm6vYnigPe+TY54DmfWYJxhMRaw/TfvrbzvE= -gopkg.in/DataDog/dd-trace-go.v1 v1.56.1/go.mod h1:KDLJ3CWVOSuVVwu+0ZR5KZo2rP6c7YyBV3v387dIpUU= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -2638,8 +2505,10 @@ gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/gorethink/gorethink.v3 v3.0.5 h1:e2Uc/Xe+hpcVQFsj6MuHlYog3r0JYpnTzwDj/y2O4MU= gopkg.in/gorethink/gorethink.v3 v3.0.5/go.mod h1:+3yIIHJUGMBK+wyPH+iN5TP+88ikFDfZdqTlK3Y9q8I= -gopkg.in/h2non/gock.v1 v1.0.15 h1:SzLqcIlb/fDfg7UvukMpNcWsu7sI5tWwL+KCATZqks0= +gopkg.in/h2non/gentleman.v1 v1.0.4/go.mod h1:JYuHVdFzS4MKOXe0o+chKJ4hCe6tqKKw9XH9YP6WFrg= gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE= +gopkg.in/h2non/gock.v1 v1.0.16 h1:F11k+OafeuFENsjei5t2vMTSTs9L62AdyTe4E1cgdG8= +gopkg.in/h2non/gock.v1 v1.0.16/go.mod h1:XVuDAssexPLwgxCLMvDTWNU5eqklsydR6I5phZ9oPB8= gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= @@ -2689,10 +2558,6 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -howett.net/plist v0.0.0-20181124034731-591f970eefbb h1:jhnBjNi9UFpfpl8YZhA9CrOqpnJdvzuiHsl/dnxl11M= -howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= -inet.af/netaddr v0.0.0-20230525184311-b8eac61e914a h1:1XCVEdxrvL6c0TGOhecLuB7U9zYNdxZEjvOqJreKZiM= -inet.af/netaddr v0.0.0-20230525184311-b8eac61e914a/go.mod h1:e83i32mAQOW1LAqEIweALsuK2Uw4mhQadA5r7b0Wobo= k8s.io/api v0.0.0-20180904230853-4e7be11eab3f/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= k8s.io/api v0.0.0-20191016110408-35e52d86657a/go.mod h1:/L5qH+AD540e7Cetbui1tuJeXdmNhO8jM6VkXeDdDhQ= k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= @@ -2756,8 +2621,8 @@ k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= k8s.io/klog/v2 v2.10.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= -k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4= -k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/klog/v2 v2.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw= +k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/kube-openapi v0.0.0-20180731170545-e3762e86a74c/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= k8s.io/kube-openapi v0.0.0-20190709113604-33be087ad058/go.mod h1:nfDlWeOsu3pUf4yWGL+ERqohP4YsZcBJXWMK+gkzOA4= k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= diff --git a/integration/fixtures/tracing/otel-collector-config.yaml b/integration/fixtures/tracing/otel-collector-config.yaml new file mode 100644 index 000000000..4f51aec4b --- /dev/null +++ b/integration/fixtures/tracing/otel-collector-config.yaml @@ -0,0 +1,21 @@ +receivers: + otlp: + protocols: + grpc: + http: +exporters: + otlp/tempo: + endpoint: http://tempo:4317 + tls: + insecure: true +service: + telemetry: + logs: + level: "error" + extensions: [ health_check ] + pipelines: + traces: + receivers: [otlp] + exporters: [otlp/tempo] +extensions: + health_check: \ No newline at end of file diff --git a/integration/fixtures/tracing/simple-jaeger.toml b/integration/fixtures/tracing/simple-jaeger.toml deleted file mode 100644 index bf02ced6a..000000000 --- a/integration/fixtures/tracing/simple-jaeger.toml +++ /dev/null @@ -1,70 +0,0 @@ -[global] - checkNewVersion = false - sendAnonymousUsage = false - -[log] - level = "DEBUG" - noColor = true - -[api] - insecure = true - -[entryPoints] - [entryPoints.web] - address = ":8000" - -[tracing] - servicename = "tracing" - [tracing.jaeger] - samplingType = "const" - samplingParam = 1.0 - samplingServerURL = "http://{{.IP}}:5778/sampling" - localAgentHostPort = "{{.IP}}:6831" - traceContextHeaderName = "{{.TraceContextHeaderName}}" - -[providers.file] - filename = "{{ .SelfFilename }}" - -## dynamic configuration ## - -[http.routers] - [http.routers.router1] - Service = "service1" - Middlewares = ["retry", "ratelimit-1"] - Rule = "Path(`/ratelimit`)" - [http.routers.router2] - Service = "service2" - Middlewares = ["retry"] - Rule = "Path(`/retry`)" - [http.routers.router3] - Service = "service3" - Middlewares = ["retry", "basic-auth"] - Rule = "Path(`/auth`)" - -[http.middlewares] - [http.middlewares.retry.retry] - attempts = 3 - [http.middlewares.basic-auth.basicAuth] - users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"] - [http.middlewares.ratelimit-1.rateLimit] - average = 1 - burst = 2 - -[http.services] - [http.services.service1] - [http.services.service1.loadBalancer] - passHostHeader = true - [[http.services.service1.loadBalancer.servers]] - url = "http://{{.WhoamiIP}}:{{.WhoamiPort}}" - - [http.services.service2] - [http.services.service2.loadBalancer] - passHostHeader = true - [[http.services.service2.loadBalancer.servers]] - url = "http://{{.WhoamiIP}}:{{.WhoamiPort}}" - - [http.services.service3] - [http.services.service3.loadBalancer] - passHostHeader = true - [[http.services.service3.loadBalancer.servers]] - url = "http://{{.WhoamiIP}}:{{.WhoamiPort}}" diff --git a/integration/fixtures/tracing/simple-jaeger-collector.toml b/integration/fixtures/tracing/simple-opentelemetry.toml similarity index 76% rename from integration/fixtures/tracing/simple-jaeger-collector.toml rename to integration/fixtures/tracing/simple-opentelemetry.toml index e858e2a57..77d779800 100644 --- a/integration/fixtures/tracing/simple-jaeger-collector.toml +++ b/integration/fixtures/tracing/simple-opentelemetry.toml @@ -15,12 +15,15 @@ [tracing] servicename = "tracing" - [tracing.jaeger] - samplingType = "const" - samplingParam = 1.0 - samplingServerURL = "http://{{.IP}}:5778/sampling" - [tracing.jaeger.collector] - endpoint = "http://{{.IP}}:14268/api/traces?format=jaeger.thrift" + sampleRate = 1.0 +{{if .IsHTTP}} + [tracing.otlp.http] + endpoint = "http://{{.IP}}:4318" +{{else}} + [tracing.otlp.grpc] + endpoint = "{{.IP}}:4317" + insecure = true +{{end}} [providers.file] filename = "{{ .SelfFilename }}" @@ -28,6 +31,10 @@ ## dynamic configuration ## [http.routers] + [http.routers.router0] + Service = "service0" + Middlewares = [] + Rule = "Path(`/basic`)" [http.routers.router1] Service = "service1" Middlewares = ["retry", "ratelimit-1"] @@ -50,8 +57,13 @@ average = 1 burst = 2 - [http.services] + [http.services.service0] + [http.services.service0.loadBalancer] + passHostHeader = true + [[http.services.service0.loadBalancer.servers]] + url = "http://{{.WhoamiIP}}:{{.WhoamiPort}}" + [http.services.service1] [http.services.service1.loadBalancer] passHostHeader = true diff --git a/integration/fixtures/tracing/simple-zipkin.toml b/integration/fixtures/tracing/simple-zipkin.toml deleted file mode 100644 index ef935fa28..000000000 --- a/integration/fixtures/tracing/simple-zipkin.toml +++ /dev/null @@ -1,66 +0,0 @@ -[global] - checkNewVersion = false - sendAnonymousUsage = false - -[log] - level = "DEBUG" - noColor = true - -[api] - insecure = true - -[entryPoints] - [entryPoints.web] - address = ":8000" - -[tracing] - servicename = "tracing" - [tracing.zipkin] - httpEndpoint = "http://{{.IP}}:9411/api/v2/spans" - -[providers.file] - filename = "{{ .SelfFilename }}" - -## dynamic configuration ## - -[http.routers] - [http.routers.router1] - service = "service1" - middlewares = ["retry", "ratelimit-1"] - rule = "Path(`/ratelimit`)" - [http.routers.router2] - service = "service2" - middlewares = ["retry"] - rule = "Path(`/retry`)" - [http.routers.router3] - service = "service3" - middlewares = ["retry", "basic-auth"] - rule = "Path(`/auth`)" - -[http.middlewares] - [http.middlewares.retry.retry] - attempts = 3 - [http.middlewares.basic-auth.basicAuth] - users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"] - [http.middlewares.ratelimit-1.rateLimit] - average = 1 - burst = 2 - -[http.services] - [http.services.service1] - [http.services.service1.loadBalancer] - passHostHeader = true - [[http.services.service1.loadBalancer.servers]] - url = "http://{{.WhoamiIP}}:{{.WhoamiPort}}" - - [http.services.service2] - [http.services.service2.loadBalancer] - passHostHeader = true - [[http.services.service2.loadBalancer.servers]] - url = "http://{{.WhoamiIP}}:{{.WhoamiPort}}" - - [http.services.service3] - [http.services.service3.loadBalancer] - passHostHeader = true - [[http.services.service3.loadBalancer.servers]] - url = "http://{{.WhoamiIP}}:{{.WhoamiPort}}" diff --git a/integration/fixtures/tracing/tempo.yaml b/integration/fixtures/tracing/tempo.yaml new file mode 100644 index 000000000..0a115bfaa --- /dev/null +++ b/integration/fixtures/tracing/tempo.yaml @@ -0,0 +1,56 @@ +server: + http_listen_port: 3200 + +query_frontend: + search: + duration_slo: 5s + throughput_bytes_slo: 1.073741824e+09 + trace_by_id: + duration_slo: 5s + +distributor: + receivers: + otlp: + protocols: + grpc: + +ingester: + lifecycler: + address: 127.0.0.1 + ring: + kvstore: + store: inmemory + replication_factor: 1 + final_sleep: 0s + trace_idle_period: 1s + max_block_duration: 1m + complete_block_timeout: 5s + flush_check_period: 1s +compactor: + compaction: + block_retention: 1h + +metrics_generator: + registry: + external_labels: + source: tempo + cluster: docker-compose + storage: + path: /tmp/tempo/generator/wal + remote_write: + - url: http://prometheus:9090/api/v1/write + send_exemplars: true + +storage: + trace: + backend: local # backend configuration to use + wal: + path: /tmp/tempo/wal # where to store the wal locally + local: + path: /tmp/tempo/blocks + +overrides: + defaults: + metrics_generator: + processors: [service-graphs, span-metrics] # enables metrics generator + diff --git a/integration/resources/compose/tracing.yml b/integration/resources/compose/tracing.yml index aeea9b378..4cd02cec0 100644 --- a/integration/resources/compose/tracing.yml +++ b/integration/resources/compose/tracing.yml @@ -1,16 +1,15 @@ version: "3.8" services: - zipkin: - image: openzipkin/zipkin:2.16.2 - environment: - STORAGE_TYPE: mem - JAVA_OPTS: -Dlogging.level.zipkin=DEBUG - - jaeger: - image: jaegertracing/all-in-one:1.14 - environment: - COLLECTOR_ZIPKIN_HTTP_PORT: 9411 - + tempo: + hostname: tempo + image: grafana/tempo:latest + command: [ "-config.file=/etc/tempo.yaml" ] + volumes: + - ./fixtures/tracing/tempo.yaml:/etc/tempo.yaml + otel-collector: + image: otel/opentelemetry-collector-contrib:0.89.0 + volumes: + - ./fixtures/tracing/otel-collector-config.yaml:/etc/otelcol-contrib/config.yaml whoami: image: traefik/whoami diff --git a/integration/tracing_test.go b/integration/tracing_test.go index f2a1f29ad..328b63d17 100644 --- a/integration/tracing_test.go +++ b/integration/tracing_test.go @@ -1,20 +1,26 @@ package integration import ( + "encoding/json" + "io" "net/http" + "net/url" "os" + "strings" "time" "github.com/go-check/check" + "github.com/tidwall/gjson" "github.com/traefik/traefik/v3/integration/try" checker "github.com/vdemeester/shakers" ) type TracingSuite struct { BaseSuite - whoamiIP string - whoamiPort int - tracerIP string + whoamiIP string + whoamiPort int + tempoIP string + otelCollectorIP string } type TracingTemplate struct { @@ -22,39 +28,157 @@ type TracingTemplate struct { WhoamiPort int IP string TraceContextHeaderName string + IsHTTP bool } func (s *TracingSuite) SetUpSuite(c *check.C) { s.createComposeProject(c, "tracing") s.composeUp(c) +} + +func (s *TracingSuite) SetUpTest(c *check.C) { + s.composeUp(c, "tempo", "otel-collector", "whoami") s.whoamiIP = s.getComposeServiceIP(c, "whoami") s.whoamiPort = 80 -} -func (s *TracingSuite) startZipkin(c *check.C) { - s.composeUp(c, "zipkin") - s.tracerIP = s.getComposeServiceIP(c, "zipkin") + // Wait for whoami to turn ready. + err := try.GetRequest("http://"+s.whoamiIP+":80", 30*time.Second, try.StatusCodeIs(http.StatusOK)) + c.Assert(err, checker.IsNil) - // Wait for Zipkin to turn ready. - err := try.GetRequest("http://"+s.tracerIP+":9411/api/v2/services", 20*time.Second, try.StatusCodeIs(http.StatusOK)) + s.tempoIP = s.getComposeServiceIP(c, "tempo") + + // Wait for tempo to turn ready. + err = try.GetRequest("http://"+s.tempoIP+":3200/ready", 30*time.Second, try.StatusCodeIs(http.StatusOK)) + c.Assert(err, checker.IsNil) + + s.otelCollectorIP = s.getComposeServiceIP(c, "otel-collector") + + // Wait for otel collector to turn ready. + err = try.GetRequest("http://"+s.otelCollectorIP+":13133/", 30*time.Second, try.StatusCodeIs(http.StatusOK)) c.Assert(err, checker.IsNil) } -func (s *TracingSuite) TestZipkinRateLimit(c *check.C) { - s.startZipkin(c) - // defer s.composeStop(c, "zipkin") +func (s *TracingSuite) TearDownTest(c *check.C) { + s.composeStop(c, "tempo") +} - file := s.adaptFile(c, "fixtures/tracing/simple-zipkin.toml", TracingTemplate{ +func (s *TracingSuite) TestOpentelemetryBasic_HTTP(c *check.C) { + file := s.adaptFile(c, "fixtures/tracing/simple-opentelemetry.toml", TracingTemplate{ WhoamiIP: s.whoamiIP, WhoamiPort: s.whoamiPort, - IP: s.tracerIP, + IP: s.otelCollectorIP, + IsHTTP: true, }) defer os.Remove(file) cmd, display := s.traefikCmd(withConfigFile(file)) defer display(c) + err := cmd.Start() + c.Assert(err, checker.IsNil) + defer s.killCmd(cmd) + // wait for traefik + err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", time.Second, try.BodyContains("basic-auth")) + c.Assert(err, checker.IsNil) + + err = try.GetRequest("http://127.0.0.1:8000/basic", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK)) + c.Assert(err, checker.IsNil) + + contains := []map[string]string{ + { + "batches.0.scopeSpans.0.scope.name": "github.com/traefik/traefik", + + "batches.0.scopeSpans.0.spans.0.name": "EntryPoint", + "batches.0.scopeSpans.0.spans.0.kind": "SPAN_KIND_SERVER", + "batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.request.method\").value.stringValue": "GET", + "batches.0.scopeSpans.0.spans.0.attributes.#(key=\"entry_point\").value.stringValue": "web", + "batches.0.scopeSpans.0.spans.0.attributes.#(key=\"url.path\").value.stringValue": "/basic", + "batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.response.status_code\").value.intValue": "200", + + "batches.0.scopeSpans.0.spans.1.name": "Router", + "batches.0.scopeSpans.0.spans.1.kind": "SPAN_KIND_INTERNAL", + "batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.router.name\").value.stringValue": "router0@file", + "batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.service.name\").value.stringValue": "service0@file", + + "batches.0.scopeSpans.0.spans.2.name": "Service", + "batches.0.scopeSpans.0.spans.2.kind": "SPAN_KIND_INTERNAL", + "batches.0.scopeSpans.0.spans.2.attributes.#(key=\"traefik.service.name\").value.stringValue": "service0@file", + + "batches.0.scopeSpans.0.spans.3.name": "ReverseProxy", + "batches.0.scopeSpans.0.spans.3.kind": "SPAN_KIND_CLIENT", + "batches.0.scopeSpans.0.spans.3.attributes.#(key=\"url.scheme\").value.stringValue": "http", + "batches.0.scopeSpans.0.spans.3.attributes.#(key=\"http.response.status_code\").value.intValue": "200", + "batches.0.scopeSpans.0.spans.3.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1", + }, + } + + checkTraceContent(c, s.tempoIP, contains) +} + +func (s *TracingSuite) TestOpentelemetryBasic_gRPC(c *check.C) { + file := s.adaptFile(c, "fixtures/tracing/simple-opentelemetry.toml", TracingTemplate{ + WhoamiIP: s.whoamiIP, + WhoamiPort: s.whoamiPort, + IP: s.otelCollectorIP, + IsHTTP: false, + }) + defer os.Remove(file) + + cmd, display := s.traefikCmd(withConfigFile(file)) + defer display(c) + err := cmd.Start() + c.Assert(err, checker.IsNil) + defer s.killCmd(cmd) + + // wait for traefik + err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", time.Second, try.BodyContains("basic-auth")) + c.Assert(err, checker.IsNil) + + err = try.GetRequest("http://127.0.0.1:8000/basic", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK)) + c.Assert(err, checker.IsNil) + + contains := []map[string]string{ + { + "batches.0.scopeSpans.0.scope.name": "github.com/traefik/traefik", + + "batches.0.scopeSpans.0.spans.0.name": "EntryPoint", + "batches.0.scopeSpans.0.spans.0.kind": "SPAN_KIND_SERVER", + "batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.request.method\").value.stringValue": "GET", + "batches.0.scopeSpans.0.spans.0.attributes.#(key=\"entry_point\").value.stringValue": "web", + "batches.0.scopeSpans.0.spans.0.attributes.#(key=\"url.path\").value.stringValue": "/basic", + "batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.response.status_code\").value.intValue": "200", + + "batches.0.scopeSpans.0.spans.1.name": "Router", + "batches.0.scopeSpans.0.spans.1.kind": "SPAN_KIND_INTERNAL", + "batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.router.name\").value.stringValue": "router0@file", + "batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.service.name\").value.stringValue": "service0@file", + + "batches.0.scopeSpans.0.spans.2.name": "Service", + "batches.0.scopeSpans.0.spans.2.kind": "SPAN_KIND_INTERNAL", + "batches.0.scopeSpans.0.spans.2.attributes.#(key=\"traefik.service.name\").value.stringValue": "service0@file", + + "batches.0.scopeSpans.0.spans.3.name": "ReverseProxy", + "batches.0.scopeSpans.0.spans.3.kind": "SPAN_KIND_CLIENT", + "batches.0.scopeSpans.0.spans.3.attributes.#(key=\"url.scheme\").value.stringValue": "http", + "batches.0.scopeSpans.0.spans.3.attributes.#(key=\"http.response.status_code\").value.intValue": "200", + "batches.0.scopeSpans.0.spans.3.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1", + }, + } + + checkTraceContent(c, s.tempoIP, contains) +} + +func (s *TracingSuite) TestOpentelemetryRateLimit(c *check.C) { + file := s.adaptFile(c, "fixtures/tracing/simple-opentelemetry.toml", TracingTemplate{ + WhoamiIP: s.whoamiIP, + WhoamiPort: s.whoamiPort, + IP: s.otelCollectorIP, + }) + defer os.Remove(file) + + cmd, display := s.traefikCmd(withConfigFile(file)) + defer display(c) err := cmd.Start() c.Assert(err, checker.IsNil) defer s.killCmd(cmd) @@ -85,22 +209,94 @@ func (s *TracingSuite) TestZipkinRateLimit(c *check.C) { err = try.GetRequest("http://127.0.0.1:8000/ratelimit", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK)) c.Assert(err, checker.IsNil) - time.Sleep(3 * time.Second) err = try.GetRequest("http://127.0.0.1:8000/ratelimit", 500*time.Millisecond, try.StatusCodeIs(http.StatusTooManyRequests)) c.Assert(err, checker.IsNil) - err = try.GetRequest("http://"+s.tracerIP+":9411/api/v2/spans?serviceName=tracing", 20*time.Second, try.BodyContains("forward service1/router1@file", "ratelimit-1@file")) - c.Assert(err, checker.IsNil) + contains := []map[string]string{ + { + "batches.0.scopeSpans.0.scope.name": "github.com/traefik/traefik", + + "batches.0.scopeSpans.0.spans.0.name": "EntryPoint", + "batches.0.scopeSpans.0.spans.0.kind": "SPAN_KIND_SERVER", + "batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.request.method\").value.stringValue": "GET", + "batches.0.scopeSpans.0.spans.0.attributes.#(key=\"entry_point\").value.stringValue": "web", + "batches.0.scopeSpans.0.spans.0.attributes.#(key=\"url.path\").value.stringValue": "/ratelimit", + "batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.response.status_code\").value.intValue": "200", + + "batches.0.scopeSpans.0.spans.1.name": "Router", + "batches.0.scopeSpans.0.spans.1.kind": "SPAN_KIND_INTERNAL", + "batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.router.name\").value.stringValue": "router1@file", + "batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.service.name\").value.stringValue": "service1@file", + + "batches.0.scopeSpans.0.spans.2.name": "Retry", + "batches.0.scopeSpans.0.spans.2.kind": "SPAN_KIND_INTERNAL", + "batches.0.scopeSpans.0.spans.2.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file", + + "batches.0.scopeSpans.0.spans.3.name": "RateLimiter", + "batches.0.scopeSpans.0.spans.3.kind": "SPAN_KIND_INTERNAL", + "batches.0.scopeSpans.0.spans.3.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "ratelimit-1@file", + + "batches.0.scopeSpans.0.spans.4.name": "Service", + "batches.0.scopeSpans.0.spans.4.kind": "SPAN_KIND_INTERNAL", + "batches.0.scopeSpans.0.spans.4.attributes.#(key=\"traefik.service.name\").value.stringValue": "service1@file", + + "batches.0.scopeSpans.0.spans.5.name": "ReverseProxy", + "batches.0.scopeSpans.0.spans.5.kind": "SPAN_KIND_CLIENT", + "batches.0.scopeSpans.0.spans.5.attributes.#(key=\"url.scheme\").value.stringValue": "http", + "batches.0.scopeSpans.0.spans.5.attributes.#(key=\"http.response.status_code\").value.intValue": "200", + "batches.0.scopeSpans.0.spans.5.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1", + }, + { + "batches.0.scopeSpans.0.scope.name": "github.com/traefik/traefik", + + "batches.0.scopeSpans.0.spans.0.name": "EntryPoint", + "batches.0.scopeSpans.0.spans.0.kind": "SPAN_KIND_SERVER", + "batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.request.method\").value.stringValue": "GET", + "batches.0.scopeSpans.0.spans.0.attributes.#(key=\"entry_point\").value.stringValue": "web", + "batches.0.scopeSpans.0.spans.0.attributes.#(key=\"url.path\").value.stringValue": "/ratelimit", + "batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.response.status_code\").value.intValue": "429", + + "batches.0.scopeSpans.0.spans.1.name": "Router", + "batches.0.scopeSpans.0.spans.1.kind": "SPAN_KIND_INTERNAL", + "batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.router.name\").value.stringValue": "router1@file", + "batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.service.name\").value.stringValue": "service1@file", + + "batches.0.scopeSpans.0.spans.2.name": "Retry", + "batches.0.scopeSpans.0.spans.2.kind": "SPAN_KIND_INTERNAL", + "batches.0.scopeSpans.0.spans.2.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file", + + "batches.0.scopeSpans.0.spans.3.name": "RateLimiter", + "batches.0.scopeSpans.0.spans.3.kind": "SPAN_KIND_INTERNAL", + "batches.0.scopeSpans.0.spans.3.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "ratelimit-1@file", + + "batches.0.scopeSpans.0.spans.4.name": "Retry", + "batches.0.scopeSpans.0.spans.4.kind": "SPAN_KIND_INTERNAL", + "batches.0.scopeSpans.0.spans.4.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file", + "batches.0.scopeSpans.0.spans.4.attributes.#(key=\"http.resend_count\").value.intValue": "1", + + "batches.0.scopeSpans.0.spans.5.name": "RateLimiter", + "batches.0.scopeSpans.0.spans.5.kind": "SPAN_KIND_INTERNAL", + "batches.0.scopeSpans.0.spans.5.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "ratelimit-1@file", + + "batches.0.scopeSpans.0.spans.6.name": "Retry", + "batches.0.scopeSpans.0.spans.6.kind": "SPAN_KIND_INTERNAL", + "batches.0.scopeSpans.0.spans.6.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file", + "batches.0.scopeSpans.0.spans.6.attributes.#(key=\"http.resend_count\").value.intValue": "2", + + "batches.0.scopeSpans.0.spans.7.name": "RateLimiter", + "batches.0.scopeSpans.0.spans.7.kind": "SPAN_KIND_INTERNAL", + "batches.0.scopeSpans.0.spans.7.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "ratelimit-1@file", + }, + } + + checkTraceContent(c, s.tempoIP, contains) } -func (s *TracingSuite) TestZipkinRetry(c *check.C) { - s.startZipkin(c) - defer s.composeStop(c, "zipkin") - - file := s.adaptFile(c, "fixtures/tracing/simple-zipkin.toml", TracingTemplate{ +func (s *TracingSuite) TestOpentelemetryRetry(c *check.C) { + file := s.adaptFile(c, "fixtures/tracing/simple-opentelemetry.toml", TracingTemplate{ WhoamiIP: s.whoamiIP, WhoamiPort: 81, - IP: s.tracerIP, + IP: s.otelCollectorIP, }) defer os.Remove(file) @@ -117,18 +313,75 @@ func (s *TracingSuite) TestZipkinRetry(c *check.C) { err = try.GetRequest("http://127.0.0.1:8000/retry", 500*time.Millisecond, try.StatusCodeIs(http.StatusBadGateway)) c.Assert(err, checker.IsNil) - err = try.GetRequest("http://"+s.tracerIP+":9411/api/v2/spans?serviceName=tracing", 20*time.Second, try.BodyContains("forward service2/router2@file", "retry@file")) - c.Assert(err, checker.IsNil) + contains := []map[string]string{ + { + "batches.0.scopeSpans.0.scope.name": "github.com/traefik/traefik", + + "batches.0.scopeSpans.0.spans.0.name": "EntryPoint", + "batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.request.method\").value.stringValue": "GET", + "batches.0.scopeSpans.0.spans.0.attributes.#(key=\"url.path\").value.stringValue": "/retry", + "batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.response.status_code\").value.intValue": "502", + "batches.0.scopeSpans.0.spans.0.status.code": "STATUS_CODE_ERROR", + + "batches.0.scopeSpans.0.spans.1.name": "Router", + "batches.0.scopeSpans.0.spans.1.kind": "SPAN_KIND_INTERNAL", + "batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.service.name\").value.stringValue": "service2@file", + "batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.router.name\").value.stringValue": "router2@file", + + "batches.0.scopeSpans.0.spans.2.name": "Retry", + "batches.0.scopeSpans.0.spans.2.kind": "SPAN_KIND_INTERNAL", + "batches.0.scopeSpans.0.spans.2.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file", + + "batches.0.scopeSpans.0.spans.3.name": "Service", + "batches.0.scopeSpans.0.spans.3.kind": "SPAN_KIND_INTERNAL", + "batches.0.scopeSpans.0.spans.3.attributes.#(key=\"traefik.service.name\").value.stringValue": "service2@file", + + "batches.0.scopeSpans.0.spans.4.name": "ReverseProxy", + "batches.0.scopeSpans.0.spans.4.kind": "SPAN_KIND_CLIENT", + "batches.0.scopeSpans.0.spans.4.attributes.#(key=\"url.scheme\").value.stringValue": "http", + "batches.0.scopeSpans.0.spans.4.attributes.#(key=\"http.response.status_code\").value.intValue": "502", + "batches.0.scopeSpans.0.spans.4.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1", + + "batches.0.scopeSpans.0.spans.5.name": "Retry", + "batches.0.scopeSpans.0.spans.5.kind": "SPAN_KIND_INTERNAL", + "batches.0.scopeSpans.0.spans.5.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file", + "batches.0.scopeSpans.0.spans.5.attributes.#(key=\"http.resend_count\").value.intValue": "1", + + "batches.0.scopeSpans.0.spans.6.name": "Service", + "batches.0.scopeSpans.0.spans.6.kind": "SPAN_KIND_INTERNAL", + "batches.0.scopeSpans.0.spans.6.attributes.#(key=\"traefik.service.name\").value.stringValue": "service2@file", + + "batches.0.scopeSpans.0.spans.7.name": "ReverseProxy", + "batches.0.scopeSpans.0.spans.7.kind": "SPAN_KIND_CLIENT", + "batches.0.scopeSpans.0.spans.7.attributes.#(key=\"url.scheme\").value.stringValue": "http", + "batches.0.scopeSpans.0.spans.7.attributes.#(key=\"http.response.status_code\").value.intValue": "502", + "batches.0.scopeSpans.0.spans.7.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1", + + "batches.0.scopeSpans.0.spans.8.name": "Retry", + "batches.0.scopeSpans.0.spans.8.kind": "SPAN_KIND_INTERNAL", + "batches.0.scopeSpans.0.spans.8.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file", + "batches.0.scopeSpans.0.spans.8.attributes.#(key=\"http.resend_count\").value.intValue": "2", + + "batches.0.scopeSpans.0.spans.9.name": "Service", + "batches.0.scopeSpans.0.spans.9.kind": "SPAN_KIND_INTERNAL", + "batches.0.scopeSpans.0.spans.9.attributes.#(key=\"traefik.service.name\").value.stringValue": "service2@file", + + "batches.0.scopeSpans.0.spans.10.name": "ReverseProxy", + "batches.0.scopeSpans.0.spans.10.kind": "SPAN_KIND_CLIENT", + "batches.0.scopeSpans.0.spans.10.attributes.#(key=\"url.scheme\").value.stringValue": "http", + "batches.0.scopeSpans.0.spans.10.attributes.#(key=\"http.response.status_code\").value.intValue": "502", + "batches.0.scopeSpans.0.spans.10.attributes.#(key=\"user_agent.original\").value.stringValue": "Go-http-client/1.1", + }, + } + + checkTraceContent(c, s.tempoIP, contains) } -func (s *TracingSuite) TestZipkinAuth(c *check.C) { - s.startZipkin(c) - defer s.composeStop(c, "zipkin") - - file := s.adaptFile(c, "fixtures/tracing/simple-zipkin.toml", TracingTemplate{ +func (s *TracingSuite) TestOpentelemetryAuth(c *check.C) { + file := s.adaptFile(c, "fixtures/tracing/simple-opentelemetry.toml", TracingTemplate{ WhoamiIP: s.whoamiIP, WhoamiPort: s.whoamiPort, - IP: s.tracerIP, + IP: s.otelCollectorIP, }) defer os.Remove(file) @@ -145,181 +398,101 @@ func (s *TracingSuite) TestZipkinAuth(c *check.C) { err = try.GetRequest("http://127.0.0.1:8000/auth", 500*time.Millisecond, try.StatusCodeIs(http.StatusUnauthorized)) c.Assert(err, checker.IsNil) - err = try.GetRequest("http://"+s.tracerIP+":9411/api/v2/spans?serviceName=tracing", 20*time.Second, try.BodyContains("entrypoint web", "basic-auth@file")) - c.Assert(err, checker.IsNil) + contains := []map[string]string{ + { + "batches.0.scopeSpans.0.scope.name": "github.com/traefik/traefik", + + "batches.0.scopeSpans.0.spans.0.name": "EntryPoint", + "batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.request.method\").value.stringValue": "GET", + "batches.0.scopeSpans.0.spans.0.attributes.#(key=\"url.path\").value.stringValue": "/auth", + "batches.0.scopeSpans.0.spans.0.attributes.#(key=\"http.response.status_code\").value.intValue": "401", + + "batches.0.scopeSpans.0.spans.1.name": "Router", + "batches.0.scopeSpans.0.spans.1.kind": "SPAN_KIND_INTERNAL", + "batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.router.name\").value.stringValue": "router3@file", + "batches.0.scopeSpans.0.spans.1.attributes.#(key=\"traefik.service.name\").value.stringValue": "service3@file", + + "batches.0.scopeSpans.0.spans.2.kind": "SPAN_KIND_INTERNAL", + "batches.0.scopeSpans.0.spans.2.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "retry@file", + + "batches.0.scopeSpans.0.spans.3.kind": "SPAN_KIND_INTERNAL", + "batches.0.scopeSpans.0.spans.3.attributes.#(key=\"traefik.middleware.name\").value.stringValue": "basic-auth@file", + }, + } + + checkTraceContent(c, s.tempoIP, contains) } -func (s *TracingSuite) startJaeger(c *check.C) { - s.composeUp(c, "jaeger", "whoami") - s.tracerIP = s.getComposeServiceIP(c, "jaeger") - - // Wait for Jaeger to turn ready. - err := try.GetRequest("http://"+s.tracerIP+":16686/api/services", 20*time.Second, try.StatusCodeIs(http.StatusOK)) +func checkTraceContent(c *check.C, tempoIP string, expectedJSON []map[string]string) { + baseURL, err := url.Parse("http://" + tempoIP + ":3200/api/search") c.Assert(err, checker.IsNil) + + req := &http.Request{ + Method: http.MethodGet, + URL: baseURL, + } + // Wait for traces to be available. + time.Sleep(10 * time.Second) + resp, err := try.Response(req, 5*time.Second) + c.Assert(err, checker.IsNil) + + out := &TraceResponse{} + content, err := io.ReadAll(resp.Body) + c.Assert(err, checker.IsNil) + err = json.Unmarshal(content, &out) + c.Assert(err, checker.IsNil) + + if len(out.Traces) == 0 { + c.Fatalf("expected at least one trace, got %d (%s)", len(out.Traces), string(content)) + } + + var contents []string + for _, t := range out.Traces { + baseURL, err := url.Parse("http://" + tempoIP + ":3200/api/traces/" + t.TraceID) + c.Assert(err, checker.IsNil) + + req := &http.Request{ + Method: http.MethodGet, + URL: baseURL, + } + + resp, err := try.Response(req, 5*time.Second) + c.Assert(err, checker.IsNil) + + content, err := io.ReadAll(resp.Body) + c.Assert(err, checker.IsNil) + + contents = append(contents, string(content)) + } + + for _, expected := range expectedJSON { + containsAll(c, expected, contents) + } } -func (s *TracingSuite) TestJaegerRateLimit(c *check.C) { - s.startJaeger(c) - defer s.composeStop(c, "jaeger") +func containsAll(c *check.C, expectedJSON map[string]string, contents []string) { + for k, v := range expectedJSON { + found := false + for _, content := range contents { + if gjson.Get(content, k).String() == v { + found = true + break + } + } - file := s.adaptFile(c, "fixtures/tracing/simple-jaeger.toml", TracingTemplate{ - WhoamiIP: s.whoamiIP, - WhoamiPort: s.whoamiPort, - IP: s.tracerIP, - TraceContextHeaderName: "uber-trace-id", - }) - defer os.Remove(file) - - cmd, display := s.traefikCmd(withConfigFile(file)) - defer display(c) - err := cmd.Start() - c.Assert(err, checker.IsNil) - defer s.killCmd(cmd) - - // wait for traefik - err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", time.Second, try.BodyContains("basic-auth")) - c.Assert(err, checker.IsNil) - - err = try.GetRequest("http://127.0.0.1:8000/ratelimit", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK)) - c.Assert(err, checker.IsNil) - err = try.GetRequest("http://127.0.0.1:8000/ratelimit", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK)) - c.Assert(err, checker.IsNil) - err = try.GetRequest("http://127.0.0.1:8000/ratelimit", 500*time.Millisecond, try.StatusCodeIs(http.StatusTooManyRequests)) - c.Assert(err, checker.IsNil) - - // sleep for 4 seconds to be certain the configured time period has elapsed - // then test another request and verify a 200 status code - time.Sleep(4 * time.Second) - err = try.GetRequest("http://127.0.0.1:8000/ratelimit", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK)) - c.Assert(err, checker.IsNil) - - // continue requests at 3 second intervals to test the other rate limit time period - time.Sleep(3 * time.Second) - err = try.GetRequest("http://127.0.0.1:8000/ratelimit", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK)) - c.Assert(err, checker.IsNil) - - time.Sleep(3 * time.Second) - err = try.GetRequest("http://127.0.0.1:8000/ratelimit", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK)) - c.Assert(err, checker.IsNil) - - err = try.GetRequest("http://127.0.0.1:8000/ratelimit", 500*time.Millisecond, try.StatusCodeIs(http.StatusTooManyRequests)) - c.Assert(err, checker.IsNil) - - err = try.GetRequest("http://"+s.tracerIP+":16686/api/traces?service=tracing", 20*time.Second, try.BodyContains("forward service1/router1@file", "ratelimit-1@file")) - c.Assert(err, checker.IsNil) + if !found { + c.Log("[" + strings.Join(contents, ",") + "]") + c.Errorf("missing element: \nKey: %q\nValue: %q ", k, v) + } + } } -func (s *TracingSuite) TestJaegerRetry(c *check.C) { - s.startJaeger(c) - defer s.composeStop(c, "jaeger") - - file := s.adaptFile(c, "fixtures/tracing/simple-jaeger.toml", TracingTemplate{ - WhoamiIP: s.whoamiIP, - WhoamiPort: 81, - IP: s.tracerIP, - TraceContextHeaderName: "uber-trace-id", - }) - defer os.Remove(file) - - cmd, display := s.traefikCmd(withConfigFile(file)) - defer display(c) - err := cmd.Start() - c.Assert(err, checker.IsNil) - defer s.killCmd(cmd) - - // wait for traefik - err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", time.Second, try.BodyContains("basic-auth")) - c.Assert(err, checker.IsNil) - - err = try.GetRequest("http://127.0.0.1:8000/retry", 500*time.Millisecond, try.StatusCodeIs(http.StatusBadGateway)) - c.Assert(err, checker.IsNil) - - err = try.GetRequest("http://"+s.tracerIP+":16686/api/traces?service=tracing", 20*time.Second, try.BodyContains("forward service2/router2@file", "retry@file")) - c.Assert(err, checker.IsNil) +// TraceResponse contains a list of traces. +type TraceResponse struct { + Traces []Trace `json:"traces"` } -func (s *TracingSuite) TestJaegerAuth(c *check.C) { - s.startJaeger(c) - defer s.composeStop(c, "jaeger") - - file := s.adaptFile(c, "fixtures/tracing/simple-jaeger.toml", TracingTemplate{ - WhoamiIP: s.whoamiIP, - WhoamiPort: s.whoamiPort, - IP: s.tracerIP, - TraceContextHeaderName: "uber-trace-id", - }) - defer os.Remove(file) - - cmd, display := s.traefikCmd(withConfigFile(file)) - defer display(c) - err := cmd.Start() - c.Assert(err, checker.IsNil) - defer s.killCmd(cmd) - - // wait for traefik - err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", time.Second, try.BodyContains("basic-auth")) - c.Assert(err, checker.IsNil) - - err = try.GetRequest("http://127.0.0.1:8000/auth", 500*time.Millisecond, try.StatusCodeIs(http.StatusUnauthorized)) - c.Assert(err, checker.IsNil) - - err = try.GetRequest("http://"+s.tracerIP+":16686/api/traces?service=tracing", 20*time.Second, try.BodyContains("EntryPoint web", "basic-auth@file")) - c.Assert(err, checker.IsNil) -} - -func (s *TracingSuite) TestJaegerCustomHeader(c *check.C) { - s.startJaeger(c) - defer s.composeStop(c, "jaeger") - - file := s.adaptFile(c, "fixtures/tracing/simple-jaeger.toml", TracingTemplate{ - WhoamiIP: s.whoamiIP, - WhoamiPort: s.whoamiPort, - IP: s.tracerIP, - TraceContextHeaderName: "powpow", - }) - defer os.Remove(file) - - cmd, display := s.traefikCmd(withConfigFile(file)) - defer display(c) - err := cmd.Start() - c.Assert(err, checker.IsNil) - defer s.killCmd(cmd) - - // wait for traefik - err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", time.Second, try.BodyContains("basic-auth")) - c.Assert(err, checker.IsNil) - - err = try.GetRequest("http://127.0.0.1:8000/auth", 500*time.Millisecond, try.StatusCodeIs(http.StatusUnauthorized)) - c.Assert(err, checker.IsNil) - - err = try.GetRequest("http://"+s.tracerIP+":16686/api/traces?service=tracing", 20*time.Second, try.BodyContains("EntryPoint web", "basic-auth@file")) - c.Assert(err, checker.IsNil) -} - -func (s *TracingSuite) TestJaegerAuthCollector(c *check.C) { - s.startJaeger(c) - defer s.composeStop(c, "jaeger") - - file := s.adaptFile(c, "fixtures/tracing/simple-jaeger-collector.toml", TracingTemplate{ - WhoamiIP: s.whoamiIP, - WhoamiPort: s.whoamiPort, - IP: s.tracerIP, - }) - defer os.Remove(file) - - cmd, display := s.traefikCmd(withConfigFile(file)) - defer display(c) - err := cmd.Start() - c.Assert(err, checker.IsNil) - defer s.killCmd(cmd) - - // wait for traefik - err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", time.Second, try.BodyContains("basic-auth")) - c.Assert(err, checker.IsNil) - - err = try.GetRequest("http://127.0.0.1:8000/auth", 500*time.Millisecond, try.StatusCodeIs(http.StatusUnauthorized)) - c.Assert(err, checker.IsNil) - - err = try.GetRequest("http://"+s.tracerIP+":16686/api/traces?service=tracing", 20*time.Second, try.BodyContains("EntryPoint web", "basic-auth@file")) - c.Assert(err, checker.IsNil) +// Trace represents a simplified grafana tempo trace. +type Trace struct { + TraceID string `json:"traceID"` } diff --git a/pkg/api/handler_overview_test.go b/pkg/api/handler_overview_test.go index 0e0165904..3e8743a81 100644 --- a/pkg/api/handler_overview_test.go +++ b/pkg/api/handler_overview_test.go @@ -18,7 +18,6 @@ import ( "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd" "github.com/traefik/traefik/v3/pkg/provider/kubernetes/ingress" "github.com/traefik/traefik/v3/pkg/provider/rest" - "github.com/traefik/traefik/v3/pkg/tracing/jaeger" "github.com/traefik/traefik/v3/pkg/types" ) @@ -259,9 +258,7 @@ func TestHandler_Overview(t *testing.T) { Metrics: &types.Metrics{ Prometheus: &types.Prometheus{}, }, - Tracing: &static.Tracing{ - Jaeger: &jaeger.Config{}, - }, + Tracing: &static.Tracing{}, }, confDyn: runtime.Configuration{}, expected: expected{ diff --git a/pkg/api/testdata/overview-features.json b/pkg/api/testdata/overview-features.json index 5df280da0..a3db11a75 100644 --- a/pkg/api/testdata/overview-features.json +++ b/pkg/api/testdata/overview-features.json @@ -2,7 +2,7 @@ "features": { "accessLog": false, "metrics": "Prometheus", - "tracing": "Jaeger" + "tracing": "" }, "http": { "middlewares": { diff --git a/pkg/config/dynamic/fixtures/sample.toml b/pkg/config/dynamic/fixtures/sample.toml index 86242772c..f6ab56cf1 100644 --- a/pkg/config/dynamic/fixtures/sample.toml +++ b/pkg/config/dynamic/fixtures/sample.toml @@ -122,41 +122,29 @@ [tracing] serviceName = "foobar" - spanNameLimit = 42 - [tracing.jaeger] - samplingServerURL = "foobar" - samplingType = "foobar" - samplingParam = 42.0 - localAgentHostPort = "foobar" - gen128Bit = true - propagation = "foobar" - traceContextHeaderName = "foobar" - [tracing.zipkin] - httpEndpoint = "foobar" - sameSpan = true - id128Bit = true - debug = true - sampleRate = 42.0 - [tracing.datadog] - localAgentHostPort = "foobar" - localAgentSocket = "foobar" - debug = true - prioritySampling = true - traceIDHeaderName = "foobar" - parentIDHeaderName = "foobar" - samplingPriorityHeaderName = "foobar" - bagagePrefixHeaderName = "foobar" - [tracing.instana] - localAgentHost = "foobar" - localAgentPort = 42 - logLevel = "foobar" - [tracing.haystack] - localAgentHost = "foobar" - localAgentPort = 42 - globalTag = "foobar" - traceIDHeaderName = "foobar" - parentIDHeaderName = "foobar" - spanIDHeaderName = "foobar" + sampleRate = 42 + [tracing.headers] + header1 = "foobar" + header2 = "foobar" + [tracing.globalAttributes] + attr1 = "foobar" + attr2 = "foobar" + [tracing.otlp.grpc] + endpoint = "foobar" + insecure = true + [tracing.otlp.grpc.tls] + ca = "foobar" + cert = "foobar" + key = "foobar" + insecureSkipVerify = true + [tracing.otlp.http] + endpoint = "foobar" + insecure = true + [tracing.otlp.http.tls] + ca = "foobar" + cert = "foobar" + key = "foobar" + insecureSkipVerify = true [hostResolver] cnameFlattening = true diff --git a/pkg/config/static/static_config.go b/pkg/config/static/static_config.go index 01a28d7c0..1c141a5a8 100644 --- a/pkg/config/static/static_config.go +++ b/pkg/config/static/static_config.go @@ -1,6 +1,7 @@ package static import ( + "errors" "fmt" "strings" "time" @@ -27,13 +28,7 @@ import ( "github.com/traefik/traefik/v3/pkg/provider/nomad" "github.com/traefik/traefik/v3/pkg/provider/rest" "github.com/traefik/traefik/v3/pkg/tls" - "github.com/traefik/traefik/v3/pkg/tracing/datadog" - "github.com/traefik/traefik/v3/pkg/tracing/elastic" - "github.com/traefik/traefik/v3/pkg/tracing/haystack" - "github.com/traefik/traefik/v3/pkg/tracing/instana" - "github.com/traefik/traefik/v3/pkg/tracing/jaeger" "github.com/traefik/traefik/v3/pkg/tracing/opentelemetry" - "github.com/traefik/traefik/v3/pkg/tracing/zipkin" "github.com/traefik/traefik/v3/pkg/types" ) @@ -187,21 +182,18 @@ 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"` - SpanNameLimit int `description:"Set the maximum character limit for Span names (default 0 = no limit)." json:"spanNameLimit,omitempty" toml:"spanNameLimit,omitempty" yaml:"spanNameLimit,omitempty" export:"true"` - Jaeger *jaeger.Config `description:"Settings for Jaeger." json:"jaeger,omitempty" toml:"jaeger,omitempty" yaml:"jaeger,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` - Zipkin *zipkin.Config `description:"Settings for Zipkin." json:"zipkin,omitempty" toml:"zipkin,omitempty" yaml:"zipkin,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` - Datadog *datadog.Config `description:"Settings for Datadog." json:"datadog,omitempty" toml:"datadog,omitempty" yaml:"datadog,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` - Instana *instana.Config `description:"Settings for Instana." json:"instana,omitempty" toml:"instana,omitempty" yaml:"instana,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` - Haystack *haystack.Config `description:"Settings for Haystack." json:"haystack,omitempty" toml:"haystack,omitempty" yaml:"haystack,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` - Elastic *elastic.Config `description:"Settings for Elastic." json:"elastic,omitempty" toml:"elastic,omitempty" yaml:"elastic,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` - OpenTelemetry *opentelemetry.Config `description:"Settings for OpenTelemetry." json:"openTelemetry,omitempty" toml:"openTelemetry,omitempty" yaml:"openTelemetry,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` + ServiceName string `description:"Set the name for this service." json:"serviceName,omitempty" toml:"serviceName,omitempty" yaml:"serviceName,omitempty" export:"true"` + Headers map[string]string `description:"Defines additional headers to be sent with the payloads." json:"headers,omitempty" toml:"headers,omitempty" yaml:"headers,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"` + 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"` + + OTLP *opentelemetry.Config `description:"Settings for OpenTelemetry." json:"otlp,omitempty" toml:"otlp,omitempty" yaml:"otlp,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` } // SetDefaults sets the default values. func (t *Tracing) SetDefaults() { t.ServiceName = "traefik" - t.SpanNameLimit = 0 + t.SampleRate = 1.0 } // Providers contains providers configuration. @@ -326,6 +318,20 @@ func (c *Configuration) ValidateConfiguration() error { acmeEmail = resolver.ACME.Email } + if c.Tracing != nil && c.Tracing.OTLP != nil { + if c.Tracing.OTLP.HTTP == nil && c.Tracing.OTLP.GRPC == nil { + return errors.New("tracing OTLP: at least one of HTTP and gRPC options should be defined") + } + + if c.Tracing.OTLP.HTTP != nil && c.Tracing.OTLP.GRPC != nil { + return errors.New("tracing OTLP: HTTP and gRPC options are mutually exclusive") + } + + 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") + } + } + return nil } diff --git a/pkg/logs/haystack.go b/pkg/logs/haystack.go deleted file mode 100644 index 6f3db7361..000000000 --- a/pkg/logs/haystack.go +++ /dev/null @@ -1,28 +0,0 @@ -package logs - -import ( - "github.com/rs/zerolog" -) - -type HaystackLogger struct { - logger zerolog.Logger -} - -func NewHaystackLogger(logger zerolog.Logger) *HaystackLogger { - return &HaystackLogger{logger: logger} -} - -// Error prints the error message. -func (l HaystackLogger) Error(format string, v ...interface{}) { - l.logger.Error().CallerSkipFrame(1).Msgf(format, v...) -} - -// Info prints the info message. -func (l HaystackLogger) Info(format string, v ...interface{}) { - l.logger.Info().CallerSkipFrame(1).Msgf(format, v...) -} - -// Debug prints the info message. -func (l HaystackLogger) Debug(format string, v ...interface{}) { - l.logger.Debug().CallerSkipFrame(1).Msgf(format, v...) -} diff --git a/pkg/logs/haystack_test.go b/pkg/logs/haystack_test.go deleted file mode 100644 index a6342bd99..000000000 --- a/pkg/logs/haystack_test.go +++ /dev/null @@ -1,24 +0,0 @@ -package logs - -import ( - "bytes" - "os" - "testing" - "time" - - "github.com/rs/zerolog" - "github.com/stretchr/testify/assert" -) - -func TestNewHaystackLogger(t *testing.T) { - buf := bytes.NewBuffer(nil) - cwb := zerolog.ConsoleWriter{Out: buf, TimeFormat: time.RFC3339, NoColor: true} - - out := zerolog.MultiLevelWriter(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339}, cwb) - - logger := NewHaystackLogger(zerolog.New(out).With().Caller().Logger()) - - logger.Info("foo") - - assert.Equal(t, " INF haystack_test.go:21 > foo\n", buf.String()) -} diff --git a/pkg/logs/jaeger.go b/pkg/logs/jaeger.go deleted file mode 100644 index 2faedc2fb..000000000 --- a/pkg/logs/jaeger.go +++ /dev/null @@ -1,23 +0,0 @@ -package logs - -import ( - "github.com/rs/zerolog" -) - -// JaegerLogger is an implementation of the Logger interface that delegates to traefik log. -type JaegerLogger struct { - logger zerolog.Logger -} - -func NewJaegerLogger(logger zerolog.Logger) *JaegerLogger { - return &JaegerLogger{logger: logger} -} - -func (l *JaegerLogger) Error(msg string) { - l.logger.Error().CallerSkipFrame(1).Msg(msg) -} - -// Infof logs a message at debug priority. -func (l *JaegerLogger) Infof(msg string, args ...interface{}) { - l.logger.Debug().CallerSkipFrame(1).Msgf(msg, args...) -} diff --git a/pkg/logs/jaeger_test.go b/pkg/logs/jaeger_test.go deleted file mode 100644 index 7ab6fe53d..000000000 --- a/pkg/logs/jaeger_test.go +++ /dev/null @@ -1,24 +0,0 @@ -package logs - -import ( - "bytes" - "os" - "testing" - "time" - - "github.com/rs/zerolog" - "github.com/stretchr/testify/assert" -) - -func TestNewJaegerLogger(t *testing.T) { - buf := bytes.NewBuffer(nil) - cwb := zerolog.ConsoleWriter{Out: buf, TimeFormat: time.RFC3339, NoColor: true} - - out := zerolog.MultiLevelWriter(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339}, cwb) - - logger := NewJaegerLogger(zerolog.New(out).With().Caller().Logger()) - - logger.Infof("foo") - - assert.Equal(t, " DBG jaeger_test.go:21 > foo\n", buf.String()) -} diff --git a/pkg/metrics/opentelemetry.go b/pkg/metrics/opentelemetry.go index a6c0c43e0..e866ff5e0 100644 --- a/pkg/metrics/opentelemetry.go +++ b/pkg/metrics/opentelemetry.go @@ -19,7 +19,7 @@ import ( "go.opentelemetry.io/otel/metric" sdkmetric "go.opentelemetry.io/otel/sdk/metric" "go.opentelemetry.io/otel/sdk/resource" - semconv "go.opentelemetry.io/otel/semconv/v1.12.0" + semconv "go.opentelemetry.io/otel/semconv/v1.21.0" "google.golang.org/grpc/credentials" "google.golang.org/grpc/encoding/gzip" ) diff --git a/pkg/middlewares/addprefix/add_prefix.go b/pkg/middlewares/addprefix/add_prefix.go index 4363da9b9..e91facaf9 100644 --- a/pkg/middlewares/addprefix/add_prefix.go +++ b/pkg/middlewares/addprefix/add_prefix.go @@ -5,10 +5,9 @@ import ( "fmt" "net/http" - "github.com/opentracing/opentracing-go/ext" "github.com/traefik/traefik/v3/pkg/config/dynamic" "github.com/traefik/traefik/v3/pkg/middlewares" - "github.com/traefik/traefik/v3/pkg/tracing" + "go.opentelemetry.io/otel/trace" ) const ( @@ -40,8 +39,8 @@ func New(ctx context.Context, next http.Handler, config dynamic.AddPrefix, name return result, nil } -func (a *addPrefix) GetTracingInformation() (string, ext.SpanKindEnum) { - return a.name, tracing.SpanKindNoneEnum +func (a *addPrefix) GetTracingInformation() (string, string, trace.SpanKind) { + return a.name, typeName, trace.SpanKindInternal } func (a *addPrefix) ServeHTTP(rw http.ResponseWriter, req *http.Request) { diff --git a/pkg/middlewares/auth/basic_auth.go b/pkg/middlewares/auth/basic_auth.go index 70e25d3a1..5a3caa26d 100644 --- a/pkg/middlewares/auth/basic_auth.go +++ b/pkg/middlewares/auth/basic_auth.go @@ -8,15 +8,15 @@ import ( "strings" goauth "github.com/abbot/go-http-auth" - "github.com/opentracing/opentracing-go/ext" "github.com/traefik/traefik/v3/pkg/config/dynamic" "github.com/traefik/traefik/v3/pkg/middlewares" "github.com/traefik/traefik/v3/pkg/middlewares/accesslog" "github.com/traefik/traefik/v3/pkg/tracing" + "go.opentelemetry.io/otel/trace" ) const ( - basicTypeName = "BasicAuth" + typeNameBasic = "BasicAuth" ) type basicAuth struct { @@ -30,7 +30,7 @@ type basicAuth struct { // NewBasic creates a basicAuth middleware. func NewBasic(ctx context.Context, next http.Handler, authConfig dynamic.BasicAuth, name string) (http.Handler, error) { - middlewares.GetLogger(ctx, name, basicTypeName).Debug().Msg("Creating middleware") + middlewares.GetLogger(ctx, name, typeNameBasic).Debug().Msg("Creating middleware") users, err := getUsers(authConfig.UsersFile, authConfig.Users, basicUserParser) if err != nil { @@ -55,12 +55,12 @@ func NewBasic(ctx context.Context, next http.Handler, authConfig dynamic.BasicAu return ba, nil } -func (b *basicAuth) GetTracingInformation() (string, ext.SpanKindEnum) { - return b.name, tracing.SpanKindNoneEnum +func (b *basicAuth) GetTracingInformation() (string, string, trace.SpanKind) { + return b.name, typeNameBasic, trace.SpanKindInternal } func (b *basicAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) { - logger := middlewares.GetLogger(req.Context(), b.name, basicTypeName) + logger := middlewares.GetLogger(req.Context(), b.name, typeNameBasic) user, password, ok := req.BasicAuth() if ok { @@ -77,7 +77,7 @@ func (b *basicAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) { if !ok { logger.Debug().Msg("Authentication failed") - tracing.SetErrorWithEvent(req, "Authentication failed") + tracing.SetStatusErrorf(req.Context(), "Authentication failed") b.auth.RequireAuth(rw, req) return diff --git a/pkg/middlewares/auth/digest_auth.go b/pkg/middlewares/auth/digest_auth.go index ea772aeb5..e02bc5883 100644 --- a/pkg/middlewares/auth/digest_auth.go +++ b/pkg/middlewares/auth/digest_auth.go @@ -8,15 +8,15 @@ import ( "strings" goauth "github.com/abbot/go-http-auth" - "github.com/opentracing/opentracing-go/ext" "github.com/traefik/traefik/v3/pkg/config/dynamic" "github.com/traefik/traefik/v3/pkg/middlewares" "github.com/traefik/traefik/v3/pkg/middlewares/accesslog" "github.com/traefik/traefik/v3/pkg/tracing" + "go.opentelemetry.io/otel/trace" ) const ( - digestTypeName = "digestAuth" + typeNameDigest = "digestAuth" ) type digestAuth struct { @@ -30,7 +30,7 @@ type digestAuth struct { // NewDigest creates a digest auth middleware. func NewDigest(ctx context.Context, next http.Handler, authConfig dynamic.DigestAuth, name string) (http.Handler, error) { - middlewares.GetLogger(ctx, name, digestTypeName).Debug().Msg("Creating middleware") + middlewares.GetLogger(ctx, name, typeNameDigest).Debug().Msg("Creating middleware") users, err := getUsers(authConfig.UsersFile, authConfig.Users, digestUserParser) if err != nil { @@ -54,12 +54,12 @@ func NewDigest(ctx context.Context, next http.Handler, authConfig dynamic.Digest return da, nil } -func (d *digestAuth) GetTracingInformation() (string, ext.SpanKindEnum) { - return d.name, tracing.SpanKindNoneEnum +func (d *digestAuth) GetTracingInformation() (string, string, trace.SpanKind) { + return d.name, typeNameDigest, trace.SpanKindInternal } func (d *digestAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) { - logger := middlewares.GetLogger(req.Context(), d.name, digestTypeName) + logger := middlewares.GetLogger(req.Context(), d.name, typeNameDigest) username, authinfo := d.auth.CheckAuth(req) if username == "" { @@ -78,13 +78,13 @@ func (d *digestAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) { if authinfo != nil && *authinfo == "stale" { logger.Debug().Msg("Digest authentication failed, possibly because out of order requests") - tracing.SetErrorWithEvent(req, "Digest authentication failed, possibly because out of order requests") + tracing.SetStatusErrorf(req.Context(), "Digest authentication failed, possibly because out of order requests") d.auth.RequireAuthStale(rw, req) return } logger.Debug().Msg("Digest authentication failed") - tracing.SetErrorWithEvent(req, "Digest authentication failed") + tracing.SetStatusErrorf(req.Context(), "Digest authentication failed") d.auth.RequireAuth(rw, req) return } diff --git a/pkg/middlewares/auth/forward.go b/pkg/middlewares/auth/forward.go index b19e37a6f..f93137469 100644 --- a/pkg/middlewares/auth/forward.go +++ b/pkg/middlewares/auth/forward.go @@ -11,21 +11,22 @@ import ( "strings" "time" - "github.com/opentracing/opentracing-go/ext" "github.com/traefik/traefik/v3/pkg/config/dynamic" "github.com/traefik/traefik/v3/pkg/middlewares" "github.com/traefik/traefik/v3/pkg/middlewares/connectionheader" "github.com/traefik/traefik/v3/pkg/tracing" "github.com/vulcand/oxy/v2/forward" "github.com/vulcand/oxy/v2/utils" + "go.opentelemetry.io/otel/trace" ) const ( - xForwardedURI = "X-Forwarded-Uri" - xForwardedMethod = "X-Forwarded-Method" - forwardedTypeName = "ForwardedAuthType" + xForwardedURI = "X-Forwarded-Uri" + xForwardedMethod = "X-Forwarded-Method" ) +const typeNameForward = "ForwardAuth" + // hopHeaders Hop-by-hop headers to be removed in the authentication request. // http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html // Proxy-Authorization header is forwarded to the authentication server (see https://tools.ietf.org/html/rfc7235#section-4.4). @@ -51,7 +52,7 @@ type forwardAuth struct { // NewForward creates a forward auth middleware. func NewForward(ctx context.Context, next http.Handler, config dynamic.ForwardAuth, name string) (http.Handler, error) { - middlewares.GetLogger(ctx, name, forwardedTypeName).Debug().Msg("Creating middleware") + middlewares.GetLogger(ctx, name, typeNameForward).Debug().Msg("Creating middleware") fa := &forwardAuth{ address: config.Address, @@ -89,30 +90,38 @@ func NewForward(ctx context.Context, next http.Handler, config dynamic.ForwardAu fa.authResponseHeadersRegex = re } - return connectionheader.Remover(fa), nil + return fa, nil } -func (fa *forwardAuth) GetTracingInformation() (string, ext.SpanKindEnum) { - return fa.name, ext.SpanKindRPCClientEnum +func (fa *forwardAuth) GetTracingInformation() (string, string, trace.SpanKind) { + return fa.name, typeNameForward, trace.SpanKindInternal } func (fa *forwardAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) { - logger := middlewares.GetLogger(req.Context(), fa.name, forwardedTypeName) + logger := middlewares.GetLogger(req.Context(), fa.name, typeNameForward) - forwardReq, err := http.NewRequest(http.MethodGet, fa.address, nil) - tracing.LogRequest(tracing.GetSpan(req), forwardReq) + req = connectionheader.Remove(req) + + forwardReq, err := http.NewRequestWithContext(req.Context(), http.MethodGet, fa.address, nil) if err != nil { logMessage := fmt.Sprintf("Error calling %s. Cause %s", fa.address, err) logger.Debug().Msg(logMessage) - tracing.SetErrorWithEvent(req, logMessage) - + tracing.SetStatusErrorf(req.Context(), logMessage) rw.WriteHeader(http.StatusInternalServerError) return } - // Ensure tracing headers are in the request before we copy the headers to the - // forwardReq. - tracing.InjectRequestHeaders(req) + var forwardSpan trace.Span + if tracer := tracing.TracerFromContext(req.Context()); tracer != nil { + var tracingCtx context.Context + tracingCtx, forwardSpan = tracer.Start(req.Context(), "AuthRequest", trace.WithSpanKind(trace.SpanKindClient)) + defer forwardSpan.End() + + forwardReq = forwardReq.WithContext(tracingCtx) + + tracing.InjectContextIntoCarrier(forwardReq) + tracing.LogClientRequest(forwardSpan, forwardReq) + } writeHeader(req, forwardReq, fa.trustForwardHeader, fa.authRequestHeaders) @@ -120,7 +129,7 @@ func (fa *forwardAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) { if forwardErr != nil { logMessage := fmt.Sprintf("Error calling %s. Cause: %s", fa.address, forwardErr) logger.Debug().Msg(logMessage) - tracing.SetErrorWithEvent(req, logMessage) + tracing.SetStatusErrorf(forwardReq.Context(), logMessage) rw.WriteHeader(http.StatusInternalServerError) return @@ -131,12 +140,18 @@ func (fa *forwardAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) { if readError != nil { logMessage := fmt.Sprintf("Error reading body %s. Cause: %s", fa.address, readError) logger.Debug().Msg(logMessage) - tracing.SetErrorWithEvent(req, logMessage) + tracing.SetStatusErrorf(forwardReq.Context(), logMessage) rw.WriteHeader(http.StatusInternalServerError) return } + // Ending the forward request span as soon as the response is handled. + // If any errors happen earlier, this span will be close by the defer instruction. + if forwardSpan != nil { + forwardSpan.End() + } + // Pass the forward response's body and selected headers if it // didn't return a response within the range of [200, 300). if forwardResponse.StatusCode < http.StatusOK || forwardResponse.StatusCode >= http.StatusMultipleChoices { @@ -152,7 +167,7 @@ func (fa *forwardAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) { if !errors.Is(err, http.ErrNoLocation) { logMessage := fmt.Sprintf("Error reading response location header %s. Cause: %s", fa.address, err) logger.Debug().Msg(logMessage) - tracing.SetErrorWithEvent(req, logMessage) + tracing.SetStatusErrorf(forwardReq.Context(), logMessage) rw.WriteHeader(http.StatusInternalServerError) return @@ -162,7 +177,7 @@ func (fa *forwardAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) { rw.Header().Set("Location", redirectURL.String()) } - tracing.LogResponseCode(tracing.GetSpan(req), forwardResponse.StatusCode) + tracing.LogResponseCode(forwardSpan, forwardResponse.StatusCode, trace.SpanKindClient) rw.WriteHeader(forwardResponse.StatusCode) if _, err = rw.Write(body); err != nil { @@ -193,6 +208,8 @@ func (fa *forwardAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) { } } + tracing.LogResponseCode(forwardSpan, forwardResponse.StatusCode, trace.SpanKindClient) + req.RequestURI = req.URL.RequestURI() fa.next.ServeHTTP(rw, req) } diff --git a/pkg/middlewares/auth/forward_test.go b/pkg/middlewares/auth/forward_test.go index 0f300fc71..e3afd6882 100644 --- a/pkg/middlewares/auth/forward_test.go +++ b/pkg/middlewares/auth/forward_test.go @@ -8,15 +8,22 @@ import ( "net/http/httptest" "testing" - "github.com/opentracing/opentracing-go" - "github.com/opentracing/opentracing-go/mocktracer" + "github.com/containous/alice" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/traefik/traefik/v3/pkg/config/dynamic" + "github.com/traefik/traefik/v3/pkg/config/static" tracingMiddleware "github.com/traefik/traefik/v3/pkg/middlewares/tracing" "github.com/traefik/traefik/v3/pkg/testhelpers" "github.com/traefik/traefik/v3/pkg/tracing" + "github.com/traefik/traefik/v3/pkg/tracing/opentelemetry" + "github.com/traefik/traefik/v3/pkg/version" "github.com/vulcand/oxy/v2/forward" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/sdk/resource" + sdktrace "go.opentelemetry.io/otel/sdk/trace" + "go.opentelemetry.io/otel/sdk/trace/tracetest" + semconv "go.opentelemetry.io/otel/semconv/v1.21.0" ) func TestForwardAuthFail(t *testing.T) { @@ -452,8 +459,8 @@ func Test_writeHeader(t *testing.T) { func TestForwardAuthUsesTracing(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if r.Header.Get("Mockpfx-Ids-Traceid") == "" { - t.Errorf("expected Mockpfx-Ids-Traceid header to be present in request") + if r.Header.Get("Traceparent") == "" { + t.Errorf("expected Traceparent header to be present in request") } })) t.Cleanup(server.Close) @@ -464,15 +471,44 @@ func TestForwardAuthUsesTracing(t *testing.T) { Address: server.URL, } - tracer := mocktracer.New() - opentracing.SetGlobalTracer(tracer) + exporter := tracetest.NewInMemoryExporter() - tr, _ := tracing.NewTracing("testApp", 100, &mockBackend{tracer}) - - next, err := NewForward(context.Background(), next, auth, "authTest") + tres, err := resource.New(context.Background(), + resource.WithAttributes(semconv.ServiceNameKey.String("traefik")), + resource.WithAttributes(semconv.ServiceVersionKey.String(version.Version)), + resource.WithFromEnv(), + resource.WithTelemetrySDK(), + ) require.NoError(t, err) - next = tracingMiddleware.NewEntryPoint(context.Background(), tr, "tracingTest", next) + tracerProvider := sdktrace.NewTracerProvider( + sdktrace.WithSampler(sdktrace.AlwaysSample()), + sdktrace.WithResource(tres), + sdktrace.WithBatcher(exporter), + ) + otel.SetTracerProvider(tracerProvider) + + config := &static.Tracing{ + ServiceName: "testApp", + SampleRate: 1, + OTLP: &opentelemetry.Config{ + HTTP: &opentelemetry.HTTP{ + Endpoint: "http://127.0.0.1:8080", + }, + }, + } + tr, closer, err := tracing.NewTracing(config) + require.NoError(t, err) + t.Cleanup(func() { + _ = closer.Close() + }) + + next, err = NewForward(context.Background(), next, auth, "authTest") + require.NoError(t, err) + + chain := alice.New(tracingMiddleware.WrapEntryPointHandler(context.Background(), tr, "tracingTest")) + next, err = chain.Then(next) + require.NoError(t, err) ts := httptest.NewServer(next) t.Cleanup(ts.Close) @@ -482,11 +518,3 @@ func TestForwardAuthUsesTracing(t *testing.T) { require.NoError(t, err) assert.Equal(t, http.StatusOK, res.StatusCode) } - -type mockBackend struct { - opentracing.Tracer -} - -func (b *mockBackend) Setup(componentName string) (opentracing.Tracer, io.Closer, error) { - return b.Tracer, io.NopCloser(nil), nil -} diff --git a/pkg/middlewares/buffering/buffering.go b/pkg/middlewares/buffering/buffering.go index 6aa2ed562..ec9100a98 100644 --- a/pkg/middlewares/buffering/buffering.go +++ b/pkg/middlewares/buffering/buffering.go @@ -4,13 +4,12 @@ import ( "context" "net/http" - "github.com/opentracing/opentracing-go/ext" "github.com/rs/zerolog" "github.com/traefik/traefik/v3/pkg/config/dynamic" "github.com/traefik/traefik/v3/pkg/logs" "github.com/traefik/traefik/v3/pkg/middlewares" - "github.com/traefik/traefik/v3/pkg/tracing" oxybuffer "github.com/vulcand/oxy/v2/buffer" + "go.opentelemetry.io/otel/trace" ) const ( @@ -49,8 +48,8 @@ func New(ctx context.Context, next http.Handler, config dynamic.Buffering, name }, nil } -func (b *buffer) GetTracingInformation() (string, ext.SpanKindEnum) { - return b.name, tracing.SpanKindNoneEnum +func (b *buffer) GetTracingInformation() (string, string, trace.SpanKind) { + return b.name, typeName, trace.SpanKindInternal } func (b *buffer) ServeHTTP(rw http.ResponseWriter, req *http.Request) { diff --git a/pkg/middlewares/circuitbreaker/circuit_breaker.go b/pkg/middlewares/circuitbreaker/circuit_breaker.go index 8445b45b8..3fa06ba23 100644 --- a/pkg/middlewares/circuitbreaker/circuit_breaker.go +++ b/pkg/middlewares/circuitbreaker/circuit_breaker.go @@ -5,7 +5,6 @@ import ( "net/http" "time" - "github.com/opentracing/opentracing-go/ext" "github.com/rs/zerolog" "github.com/rs/zerolog/log" "github.com/traefik/traefik/v3/pkg/config/dynamic" @@ -13,6 +12,7 @@ import ( "github.com/traefik/traefik/v3/pkg/middlewares" "github.com/traefik/traefik/v3/pkg/tracing" "github.com/vulcand/oxy/v2/cbreaker" + "go.opentelemetry.io/otel/trace" ) const typeName = "CircuitBreaker" @@ -32,7 +32,7 @@ func New(ctx context.Context, next http.Handler, confCircuitBreaker dynamic.Circ cbOpts := []cbreaker.Option{ cbreaker.Fallback(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { - tracing.SetErrorWithEvent(req, "blocked by circuit-breaker (%q)", expression) + tracing.SetStatusErrorf(req.Context(), "blocked by circuit-breaker (%q)", expression) rw.WriteHeader(http.StatusServiceUnavailable) if _, err := rw.Write([]byte(http.StatusText(http.StatusServiceUnavailable))); err != nil { @@ -66,8 +66,8 @@ func New(ctx context.Context, next http.Handler, confCircuitBreaker dynamic.Circ }, nil } -func (c *circuitBreaker) GetTracingInformation() (string, ext.SpanKindEnum) { - return c.name, tracing.SpanKindNoneEnum +func (c *circuitBreaker) GetTracingInformation() (string, string, trace.SpanKind) { + return c.name, typeName, trace.SpanKindInternal } func (c *circuitBreaker) ServeHTTP(rw http.ResponseWriter, req *http.Request) { diff --git a/pkg/middlewares/compress/compress.go b/pkg/middlewares/compress/compress.go index adc346237..b7ae85b4d 100644 --- a/pkg/middlewares/compress/compress.go +++ b/pkg/middlewares/compress/compress.go @@ -9,11 +9,10 @@ import ( "strings" "github.com/klauspost/compress/gzhttp" - "github.com/opentracing/opentracing-go/ext" "github.com/traefik/traefik/v3/pkg/config/dynamic" "github.com/traefik/traefik/v3/pkg/middlewares" "github.com/traefik/traefik/v3/pkg/middlewares/compress/brotli" - "github.com/traefik/traefik/v3/pkg/tracing" + "go.opentelemetry.io/otel/trace" ) const typeName = "Compress" @@ -114,8 +113,8 @@ func (c *compress) ServeHTTP(rw http.ResponseWriter, req *http.Request) { c.next.ServeHTTP(rw, req) } -func (c *compress) GetTracingInformation() (string, ext.SpanKindEnum) { - return c.name, tracing.SpanKindNoneEnum +func (c *compress) GetTracingInformation() (string, string, trace.SpanKind) { + return c.name, typeName, trace.SpanKindInternal } func (c *compress) newGzipHandler() (http.Handler, error) { diff --git a/pkg/middlewares/connectionheader/connectionheader.go b/pkg/middlewares/connectionheader/connectionheader.go index b7a64910a..12a994f17 100644 --- a/pkg/middlewares/connectionheader/connectionheader.go +++ b/pkg/middlewares/connectionheader/connectionheader.go @@ -17,24 +17,29 @@ const ( // See RFC 7230, section 6.1. func Remover(next http.Handler) http.HandlerFunc { return func(rw http.ResponseWriter, req *http.Request) { - var reqUpType string - if httpguts.HeaderValuesContainsToken(req.Header[connectionHeader], upgradeHeader) { - reqUpType = req.Header.Get(upgradeHeader) - } - - removeConnectionHeaders(req.Header) - - if reqUpType != "" { - req.Header.Set(connectionHeader, upgradeHeader) - req.Header.Set(upgradeHeader, reqUpType) - } else { - req.Header.Del(connectionHeader) - } - - next.ServeHTTP(rw, req) + next.ServeHTTP(rw, Remove(req)) } } +// Remove removes hop-by-hop header on the request. +func Remove(req *http.Request) *http.Request { + var reqUpType string + if httpguts.HeaderValuesContainsToken(req.Header[connectionHeader], upgradeHeader) { + reqUpType = req.Header.Get(upgradeHeader) + } + + removeConnectionHeaders(req.Header) + + if reqUpType != "" { + req.Header.Set(connectionHeader, upgradeHeader) + req.Header.Set(upgradeHeader, reqUpType) + } else { + req.Header.Del(connectionHeader) + } + + return req +} + func removeConnectionHeaders(h http.Header) { for _, f := range h[connectionHeader] { for _, sf := range strings.Split(f, ",") { diff --git a/pkg/middlewares/customerrors/custom_errors.go b/pkg/middlewares/customerrors/custom_errors.go index 2d71e751d..dd1f77e33 100644 --- a/pkg/middlewares/customerrors/custom_errors.go +++ b/pkg/middlewares/customerrors/custom_errors.go @@ -10,12 +10,12 @@ import ( "strconv" "strings" - "github.com/opentracing/opentracing-go/ext" "github.com/traefik/traefik/v3/pkg/config/dynamic" "github.com/traefik/traefik/v3/pkg/middlewares" "github.com/traefik/traefik/v3/pkg/tracing" "github.com/traefik/traefik/v3/pkg/types" "github.com/vulcand/oxy/v2/utils" + "go.opentelemetry.io/otel/trace" ) // Compile time validation that the response recorder implements http interfaces correctly. @@ -24,7 +24,7 @@ var ( _ middlewares.Stateful = &codeCatcher{} ) -const typeName = "customError" +const typeName = "CustomError" type serviceBuilder interface { BuildHTTP(ctx context.Context, serviceName string) (http.Handler, error) @@ -62,8 +62,8 @@ func New(ctx context.Context, next http.Handler, config dynamic.ErrorPage, servi }, nil } -func (c *customErrors) GetTracingInformation() (string, ext.SpanKindEnum) { - return c.name, tracing.SpanKindNoneEnum +func (c *customErrors) GetTracingInformation() (string, string, trace.SpanKind) { + return c.name, typeName, trace.SpanKindInternal } func (c *customErrors) ServeHTTP(rw http.ResponseWriter, req *http.Request) { @@ -71,7 +71,7 @@ func (c *customErrors) ServeHTTP(rw http.ResponseWriter, req *http.Request) { if c.backendHandler == nil { logger.Error().Msg("Error pages: no backend handler.") - tracing.SetErrorWithEvent(req, "Error pages: no backend handler.") + tracing.SetStatusErrorf(req.Context(), "Error pages: no backend handler.") c.next.ServeHTTP(rw, req) return } @@ -96,12 +96,12 @@ func (c *customErrors) ServeHTTP(rw http.ResponseWriter, req *http.Request) { pageReq, err := newRequest("http://" + req.Host + query) if err != nil { logger.Error().Err(err).Send() + tracing.SetStatusErrorf(req.Context(), err.Error()) http.Error(rw, http.StatusText(code), code) return } utils.CopyHeaders(pageReq.Header, req.Header) - c.backendHandler.ServeHTTP(newCodeModifier(rw, code), pageReq.WithContext(req.Context())) } diff --git a/pkg/middlewares/grpcweb/grpcweb.go b/pkg/middlewares/grpcweb/grpcweb.go index 18fe108eb..1d32b5273 100644 --- a/pkg/middlewares/grpcweb/grpcweb.go +++ b/pkg/middlewares/grpcweb/grpcweb.go @@ -9,7 +9,7 @@ import ( "github.com/traefik/traefik/v3/pkg/middlewares" ) -const typeName = "grpc-web" +const typeName = "GRPCWeb" // New builds a new gRPC web request converter. func New(ctx context.Context, next http.Handler, config dynamic.GrpcWeb, name string) http.Handler { diff --git a/pkg/middlewares/headers/headers.go b/pkg/middlewares/headers/headers.go index 1210f6711..e393aa1a6 100644 --- a/pkg/middlewares/headers/headers.go +++ b/pkg/middlewares/headers/headers.go @@ -6,11 +6,10 @@ import ( "errors" "net/http" - "github.com/opentracing/opentracing-go/ext" "github.com/traefik/traefik/v3/pkg/config/dynamic" "github.com/traefik/traefik/v3/pkg/middlewares" "github.com/traefik/traefik/v3/pkg/middlewares/connectionheader" - "github.com/traefik/traefik/v3/pkg/tracing" + "go.opentelemetry.io/otel/trace" ) const ( @@ -61,8 +60,8 @@ func New(ctx context.Context, next http.Handler, cfg dynamic.Headers, name strin }, nil } -func (h *headers) GetTracingInformation() (string, ext.SpanKindEnum) { - return h.name, tracing.SpanKindNoneEnum +func (h *headers) GetTracingInformation() (string, string, trace.SpanKind) { + return h.name, typeName, trace.SpanKindInternal } func (h *headers) ServeHTTP(rw http.ResponseWriter, req *http.Request) { diff --git a/pkg/middlewares/headers/headers_test.go b/pkg/middlewares/headers/headers_test.go index 61cf3779a..8e365ab54 100644 --- a/pkg/middlewares/headers/headers_test.go +++ b/pkg/middlewares/headers/headers_test.go @@ -14,7 +14,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/traefik/traefik/v3/pkg/config/dynamic" - "github.com/traefik/traefik/v3/pkg/tracing" + "go.opentelemetry.io/otel/trace" ) func TestNew_withoutOptions(t *testing.T) { @@ -109,10 +109,11 @@ func Test_headers_getTracingInformation(t *testing.T) { name: "testing", } - name, trace := mid.GetTracingInformation() + name, typeName, spanKind := mid.GetTracingInformation() assert.Equal(t, "testing", name) - assert.Equal(t, tracing.SpanKindNoneEnum, trace) + assert.Equal(t, "Headers", typeName) + assert.Equal(t, trace.SpanKindInternal, spanKind) } // This test is an adapted version of net/http/httputil.Test1xxResponses test. diff --git a/pkg/middlewares/inflightreq/inflight_req.go b/pkg/middlewares/inflightreq/inflight_req.go index a6fcdf101..c05193607 100644 --- a/pkg/middlewares/inflightreq/inflight_req.go +++ b/pkg/middlewares/inflightreq/inflight_req.go @@ -5,13 +5,12 @@ import ( "fmt" "net/http" - "github.com/opentracing/opentracing-go/ext" "github.com/rs/zerolog" "github.com/traefik/traefik/v3/pkg/config/dynamic" "github.com/traefik/traefik/v3/pkg/logs" "github.com/traefik/traefik/v3/pkg/middlewares" - "github.com/traefik/traefik/v3/pkg/tracing" "github.com/vulcand/oxy/v2/connlimit" + "go.opentelemetry.io/otel/trace" ) const ( @@ -54,8 +53,8 @@ func New(ctx context.Context, next http.Handler, config dynamic.InFlightReq, nam return &inFlightReq{handler: handler, name: name}, nil } -func (i *inFlightReq) GetTracingInformation() (string, ext.SpanKindEnum) { - return i.name, tracing.SpanKindNoneEnum +func (i *inFlightReq) GetTracingInformation() (string, string, trace.SpanKind) { + return i.name, typeName, trace.SpanKindInternal } func (i *inFlightReq) ServeHTTP(rw http.ResponseWriter, req *http.Request) { diff --git a/pkg/middlewares/ipallowlist/ip_allowlist.go b/pkg/middlewares/ipallowlist/ip_allowlist.go index e888d5d92..ddd7bfe47 100644 --- a/pkg/middlewares/ipallowlist/ip_allowlist.go +++ b/pkg/middlewares/ipallowlist/ip_allowlist.go @@ -6,12 +6,12 @@ import ( "fmt" "net/http" - "github.com/opentracing/opentracing-go/ext" "github.com/rs/zerolog/log" "github.com/traefik/traefik/v3/pkg/config/dynamic" "github.com/traefik/traefik/v3/pkg/ip" "github.com/traefik/traefik/v3/pkg/middlewares" "github.com/traefik/traefik/v3/pkg/tracing" + "go.opentelemetry.io/otel/trace" ) const ( @@ -55,8 +55,8 @@ func New(ctx context.Context, next http.Handler, config dynamic.IPAllowList, nam }, nil } -func (al *ipAllowLister) GetTracingInformation() (string, ext.SpanKindEnum) { - return al.name, tracing.SpanKindNoneEnum +func (al *ipAllowLister) GetTracingInformation() (string, string, trace.SpanKind) { + return al.name, typeName, trace.SpanKindInternal } func (al *ipAllowLister) ServeHTTP(rw http.ResponseWriter, req *http.Request) { @@ -68,7 +68,7 @@ func (al *ipAllowLister) ServeHTTP(rw http.ResponseWriter, req *http.Request) { if err != nil { msg := fmt.Sprintf("Rejecting IP %s: %v", clientIP, err) logger.Debug().Msg(msg) - tracing.SetErrorWithEvent(req, msg) + tracing.SetStatusErrorf(req.Context(), msg) reject(ctx, rw) return } diff --git a/pkg/middlewares/metrics/metrics.go b/pkg/middlewares/metrics/metrics.go index 64a09db17..a61da207e 100644 --- a/pkg/middlewares/metrics/metrics.go +++ b/pkg/middlewares/metrics/metrics.go @@ -16,6 +16,8 @@ import ( "github.com/traefik/traefik/v3/pkg/middlewares/capture" "github.com/traefik/traefik/v3/pkg/middlewares/retry" traefiktls "github.com/traefik/traefik/v3/pkg/tls" + "github.com/traefik/traefik/v3/pkg/tracing" + "go.opentelemetry.io/otel/trace" "google.golang.org/grpc/codes" ) @@ -39,6 +41,7 @@ type metricsMiddleware struct { reqsBytesCounter gokitmetrics.Counter respsBytesCounter gokitmetrics.Counter baseLabels []string + name string } // NewEntryPointMiddleware creates a new metrics middleware for an Entrypoint. @@ -53,6 +56,7 @@ func NewEntryPointMiddleware(ctx context.Context, next http.Handler, registry me reqsBytesCounter: registry.EntryPointReqsBytesCounter(), respsBytesCounter: registry.EntryPointRespsBytesCounter(), baseLabels: []string{"entrypoint", entryPointName}, + name: nameEntrypoint, } } @@ -68,6 +72,7 @@ func NewRouterMiddleware(ctx context.Context, next http.Handler, registry metric reqsBytesCounter: registry.RouterReqsBytesCounter(), respsBytesCounter: registry.RouterRespsBytesCounter(), baseLabels: []string{"router", routerName, "service", serviceName}, + name: nameRouter, } } @@ -83,6 +88,7 @@ func NewServiceMiddleware(ctx context.Context, next http.Handler, registry metri reqsBytesCounter: registry.ServiceReqsBytesCounter(), respsBytesCounter: registry.ServiceRespsBytesCounter(), baseLabels: []string{"service", serviceName}, + name: nameService, } } @@ -100,6 +106,17 @@ func WrapRouterHandler(ctx context.Context, registry metrics.Registry, routerNam } } +// WrapServiceHandler Wraps metrics service to alice.Constructor. +func WrapServiceHandler(ctx context.Context, registry metrics.Registry, serviceName string) alice.Constructor { + return func(next http.Handler) (http.Handler, error) { + return NewServiceMiddleware(ctx, next, registry, serviceName), nil + } +} + +func (m *metricsMiddleware) GetTracingInformation() (string, string, trace.SpanKind) { + return m.name, typeName, trace.SpanKindInternal +} + func (m *metricsMiddleware) ServeHTTP(rw http.ResponseWriter, req *http.Request) { proto := getRequestProtocol(req) @@ -127,6 +144,7 @@ func (m *metricsMiddleware) ServeHTTP(rw http.ResponseWriter, req *http.Request) } logger := with.Logger() logger.Error().Err(err).Msg("Could not get Capture") + tracing.SetStatusErrorf(req.Context(), "Could not get Capture") return } diff --git a/pkg/middlewares/passtlsclientcert/pass_tls_client_cert.go b/pkg/middlewares/passtlsclientcert/pass_tls_client_cert.go index 94367ce28..77f1cd09d 100644 --- a/pkg/middlewares/passtlsclientcert/pass_tls_client_cert.go +++ b/pkg/middlewares/passtlsclientcert/pass_tls_client_cert.go @@ -11,11 +11,10 @@ import ( "net/url" "strings" - "github.com/opentracing/opentracing-go/ext" "github.com/rs/zerolog/log" "github.com/traefik/traefik/v3/pkg/config/dynamic" "github.com/traefik/traefik/v3/pkg/middlewares" - "github.com/traefik/traefik/v3/pkg/tracing" + "go.opentelemetry.io/otel/trace" ) const typeName = "PassClientTLSCert" @@ -140,8 +139,8 @@ func New(ctx context.Context, next http.Handler, config dynamic.PassTLSClientCer }, nil } -func (p *passTLSClientCert) GetTracingInformation() (string, ext.SpanKindEnum) { - return p.name, tracing.SpanKindNoneEnum +func (p *passTLSClientCert) GetTracingInformation() (string, string, trace.SpanKind) { + return p.name, typeName, trace.SpanKindInternal } func (p *passTLSClientCert) ServeHTTP(rw http.ResponseWriter, req *http.Request) { diff --git a/pkg/middlewares/ratelimiter/rate_limiter.go b/pkg/middlewares/ratelimiter/rate_limiter.go index 1c3582c4e..fcede7dce 100644 --- a/pkg/middlewares/ratelimiter/rate_limiter.go +++ b/pkg/middlewares/ratelimiter/rate_limiter.go @@ -9,17 +9,17 @@ import ( "time" "github.com/mailgun/ttlmap" - "github.com/opentracing/opentracing-go/ext" "github.com/rs/zerolog/log" "github.com/traefik/traefik/v3/pkg/config/dynamic" "github.com/traefik/traefik/v3/pkg/middlewares" "github.com/traefik/traefik/v3/pkg/tracing" "github.com/vulcand/oxy/v2/utils" + "go.opentelemetry.io/otel/trace" "golang.org/x/time/rate" ) const ( - typeName = "RateLimiterType" + typeName = "RateLimiter" maxSources = 65536 ) @@ -122,8 +122,8 @@ func New(ctx context.Context, next http.Handler, config dynamic.RateLimit, name }, nil } -func (rl *rateLimiter) GetTracingInformation() (string, ext.SpanKindEnum) { - return rl.name, tracing.SpanKindNoneEnum +func (rl *rateLimiter) GetTracingInformation() (string, string, trace.SpanKind) { + return rl.name, typeName, trace.SpanKindInternal } func (rl *rateLimiter) ServeHTTP(rw http.ResponseWriter, req *http.Request) { @@ -153,12 +153,14 @@ func (rl *rateLimiter) ServeHTTP(rw http.ResponseWriter, req *http.Request) { // as the expiryTime is supposed to reflect the activity (or lack thereof) on that source. if err := rl.buckets.Set(source, bucket, rl.ttl); err != nil { logger.Error().Err(err).Msg("Could not insert/update bucket") + tracing.SetStatusErrorf(req.Context(), "Could not insert/update bucket") http.Error(rw, "could not insert/update bucket", http.StatusInternalServerError) return } res := bucket.Reserve() if !res.OK() { + tracing.SetStatusErrorf(req.Context(), "No bursty traffic allowed") http.Error(rw, "No bursty traffic allowed", http.StatusTooManyRequests) return } diff --git a/pkg/middlewares/redirect/redirect.go b/pkg/middlewares/redirect/redirect.go index d64d8cd70..25ca6a2ac 100644 --- a/pkg/middlewares/redirect/redirect.go +++ b/pkg/middlewares/redirect/redirect.go @@ -5,9 +5,8 @@ import ( "net/url" "regexp" - "github.com/opentracing/opentracing-go/ext" - "github.com/traefik/traefik/v3/pkg/tracing" "github.com/vulcand/oxy/v2/utils" + "go.opentelemetry.io/otel/trace" ) const ( @@ -15,6 +14,8 @@ const ( schemeHTTPS = "https" ) +const typeName = "Redirect" + var uriRegexp = regexp.MustCompile(`^(https?):\/\/(\[[\w:.]+\]|[\w\._-]+)?(:\d+)?(.*)$`) type redirect struct { @@ -45,8 +46,8 @@ func newRedirect(next http.Handler, regex, replacement string, permanent bool, r }, nil } -func (r *redirect) GetTracingInformation() (string, ext.SpanKindEnum) { - return r.name, tracing.SpanKindNoneEnum +func (r *redirect) GetTracingInformation() (string, string, trace.SpanKind) { + return r.name, typeName, trace.SpanKindInternal } func (r *redirect) ServeHTTP(rw http.ResponseWriter, req *http.Request) { diff --git a/pkg/middlewares/replacepath/replace_path.go b/pkg/middlewares/replacepath/replace_path.go index 9f6fea443..3419d7b83 100644 --- a/pkg/middlewares/replacepath/replace_path.go +++ b/pkg/middlewares/replacepath/replace_path.go @@ -5,10 +5,10 @@ import ( "net/http" "net/url" - "github.com/opentracing/opentracing-go/ext" "github.com/traefik/traefik/v3/pkg/config/dynamic" "github.com/traefik/traefik/v3/pkg/middlewares" "github.com/traefik/traefik/v3/pkg/tracing" + "go.opentelemetry.io/otel/trace" ) const ( @@ -35,8 +35,8 @@ func New(ctx context.Context, next http.Handler, config dynamic.ReplacePath, nam }, nil } -func (r *replacePath) GetTracingInformation() (string, ext.SpanKindEnum) { - return r.name, tracing.SpanKindNoneEnum +func (r *replacePath) GetTracingInformation() (string, string, trace.SpanKind) { + return r.name, typeName, trace.SpanKindInternal } func (r *replacePath) ServeHTTP(rw http.ResponseWriter, req *http.Request) { @@ -52,6 +52,7 @@ func (r *replacePath) ServeHTTP(rw http.ResponseWriter, req *http.Request) { req.URL.Path, err = url.PathUnescape(req.URL.RawPath) if err != nil { middlewares.GetLogger(context.Background(), r.name, typeName).Error().Err(err).Send() + tracing.SetStatusErrorf(req.Context(), err.Error()) http.Error(rw, err.Error(), http.StatusInternalServerError) return } diff --git a/pkg/middlewares/replacepathregex/replace_path_regex.go b/pkg/middlewares/replacepathregex/replace_path_regex.go index 1fffb6bd4..ff800d354 100644 --- a/pkg/middlewares/replacepathregex/replace_path_regex.go +++ b/pkg/middlewares/replacepathregex/replace_path_regex.go @@ -8,11 +8,11 @@ import ( "regexp" "strings" - "github.com/opentracing/opentracing-go/ext" "github.com/traefik/traefik/v3/pkg/config/dynamic" "github.com/traefik/traefik/v3/pkg/middlewares" "github.com/traefik/traefik/v3/pkg/middlewares/replacepath" "github.com/traefik/traefik/v3/pkg/tracing" + "go.opentelemetry.io/otel/trace" ) const typeName = "ReplacePathRegex" @@ -42,8 +42,8 @@ func New(ctx context.Context, next http.Handler, config dynamic.ReplacePathRegex }, nil } -func (rp *replacePathRegex) GetTracingInformation() (string, ext.SpanKindEnum) { - return rp.name, tracing.SpanKindNoneEnum +func (rp *replacePathRegex) GetTracingInformation() (string, string, trace.SpanKind) { + return rp.name, typeName, trace.SpanKindInternal } func (rp *replacePathRegex) ServeHTTP(rw http.ResponseWriter, req *http.Request) { @@ -63,6 +63,7 @@ func (rp *replacePathRegex) ServeHTTP(rw http.ResponseWriter, req *http.Request) req.URL.Path, err = url.PathUnescape(req.URL.RawPath) if err != nil { middlewares.GetLogger(context.Background(), rp.name, typeName).Error().Err(err).Send() + tracing.SetStatusErrorf(req.Context(), err.Error()) http.Error(rw, err.Error(), http.StatusInternalServerError) return } diff --git a/pkg/middlewares/retry/retry.go b/pkg/middlewares/retry/retry.go index 68bfdadd4..f8945a989 100644 --- a/pkg/middlewares/retry/retry.go +++ b/pkg/middlewares/retry/retry.go @@ -12,10 +12,12 @@ import ( "time" "github.com/cenkalti/backoff/v4" - "github.com/opentracing/opentracing-go/ext" "github.com/traefik/traefik/v3/pkg/config/dynamic" "github.com/traefik/traefik/v3/pkg/middlewares" "github.com/traefik/traefik/v3/pkg/tracing" + "go.opentelemetry.io/otel/attribute" + semconv "go.opentelemetry.io/otel/semconv/v1.21.0" + "go.opentelemetry.io/otel/trace" ) // Compile time validation that the response writer implements http interfaces correctly. @@ -60,10 +62,6 @@ func New(ctx context.Context, next http.Handler, config dynamic.Retry, listener }, nil } -func (r *retry) GetTracingInformation() (string, ext.SpanKindEnum) { - return r.name, tracing.SpanKindNoneEnum -} - func (r *retry) ServeHTTP(rw http.ResponseWriter, req *http.Request) { if r.attempts == 1 { r.next.ServeHTTP(rw, req) @@ -79,12 +77,35 @@ func (r *retry) ServeHTTP(rw http.ResponseWriter, req *http.Request) { attempts := 1 + initialCtx := req.Context() + tracer := tracing.TracerFromContext(initialCtx) + + var currentSpan trace.Span operation := func() error { + if tracer != nil { + if currentSpan != nil { + currentSpan.End() + } + // Because multiple tracing spans may need to be created, + // the Retry middleware does not implement trace.Traceable, + // and creates directly a new span for each retry operation. + var tracingCtx context.Context + tracingCtx, currentSpan = tracer.Start(initialCtx, typeName, trace.WithSpanKind(trace.SpanKindInternal)) + + currentSpan.SetAttributes(attribute.String("traefik.middleware.name", r.name)) + // Only add the attribute "http.resend_count" defined by semantic conventions starting from second attempt. + if attempts > 1 { + currentSpan.SetAttributes(semconv.HTTPResendCount(attempts - 1)) + } + + req = req.WithContext(tracingCtx) + } + shouldRetry := attempts < r.attempts retryResponseWriter := newResponseWriter(rw, shouldRetry) // Disable retries when the backend already received request data - trace := &httptrace.ClientTrace{ + clientTrace := &httptrace.ClientTrace{ WroteHeaders: func() { retryResponseWriter.DisableRetries() }, @@ -92,7 +113,7 @@ func (r *retry) ServeHTTP(rw http.ResponseWriter, req *http.Request) { retryResponseWriter.DisableRetries() }, } - newCtx := httptrace.WithClientTrace(req.Context(), trace) + newCtx := httptrace.WithClientTrace(req.Context(), clientTrace) r.next.ServeHTTP(retryResponseWriter, req.Clone(newCtx)) @@ -119,6 +140,10 @@ func (r *retry) ServeHTTP(rw http.ResponseWriter, req *http.Request) { if err != nil { logger.Debug().Err(err).Msg("Final retry attempt failed") } + + if currentSpan != nil { + currentSpan.End() + } } func (r *retry) newBackOff() backoff.BackOff { diff --git a/pkg/middlewares/stripprefix/strip_prefix.go b/pkg/middlewares/stripprefix/strip_prefix.go index a017c051f..18717875e 100644 --- a/pkg/middlewares/stripprefix/strip_prefix.go +++ b/pkg/middlewares/stripprefix/strip_prefix.go @@ -5,10 +5,9 @@ import ( "net/http" "strings" - "github.com/opentracing/opentracing-go/ext" "github.com/traefik/traefik/v3/pkg/config/dynamic" "github.com/traefik/traefik/v3/pkg/middlewares" - "github.com/traefik/traefik/v3/pkg/tracing" + "go.opentelemetry.io/otel/trace" ) const ( @@ -34,8 +33,8 @@ func New(ctx context.Context, next http.Handler, config dynamic.StripPrefix, nam }, nil } -func (s *stripPrefix) GetTracingInformation() (string, ext.SpanKindEnum) { - return s.name, tracing.SpanKindNoneEnum +func (s *stripPrefix) GetTracingInformation() (string, string, trace.SpanKind) { + return s.name, typeName, trace.SpanKindUnspecified } func (s *stripPrefix) ServeHTTP(rw http.ResponseWriter, req *http.Request) { diff --git a/pkg/middlewares/stripprefixregex/strip_prefix_regex.go b/pkg/middlewares/stripprefixregex/strip_prefix_regex.go index 383ce1f01..71de1ad28 100644 --- a/pkg/middlewares/stripprefixregex/strip_prefix_regex.go +++ b/pkg/middlewares/stripprefixregex/strip_prefix_regex.go @@ -6,11 +6,10 @@ import ( "regexp" "strings" - "github.com/opentracing/opentracing-go/ext" "github.com/traefik/traefik/v3/pkg/config/dynamic" "github.com/traefik/traefik/v3/pkg/middlewares" "github.com/traefik/traefik/v3/pkg/middlewares/stripprefix" - "github.com/traefik/traefik/v3/pkg/tracing" + "go.opentelemetry.io/otel/trace" ) const ( @@ -44,8 +43,8 @@ func New(ctx context.Context, next http.Handler, config dynamic.StripPrefixRegex return &stripPrefix, nil } -func (s *stripPrefixRegex) GetTracingInformation() (string, ext.SpanKindEnum) { - return s.name, tracing.SpanKindNoneEnum +func (s *stripPrefixRegex) GetTracingInformation() (string, string, trace.SpanKind) { + return s.name, typeName, trace.SpanKindInternal } func (s *stripPrefixRegex) ServeHTTP(rw http.ResponseWriter, req *http.Request) { diff --git a/pkg/middlewares/tracing/entrypoint.go b/pkg/middlewares/tracing/entrypoint.go index b17d8c2ce..5ea32ee8f 100644 --- a/pkg/middlewares/tracing/entrypoint.go +++ b/pkg/middlewares/tracing/entrypoint.go @@ -5,57 +5,53 @@ import ( "net/http" "github.com/containous/alice" - "github.com/opentracing/opentracing-go" - "github.com/opentracing/opentracing-go/ext" "github.com/traefik/traefik/v3/pkg/middlewares" "github.com/traefik/traefik/v3/pkg/tracing" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" ) const ( entryPointTypeName = "TracingEntryPoint" ) -// NewEntryPoint creates a new middleware that the incoming request. -func NewEntryPoint(ctx context.Context, t *tracing.Tracing, entryPointName string, next http.Handler) http.Handler { - middlewares.GetLogger(ctx, "tracing", entryPointTypeName).Debug().Msg("Creating middleware") - - return &entryPointMiddleware{ - entryPoint: entryPointName, - Tracing: t, - next: next, - } -} - -type entryPointMiddleware struct { - *tracing.Tracing +type entryPointTracing struct { + tracer trace.Tracer entryPoint string next http.Handler } -func (e *entryPointMiddleware) ServeHTTP(rw http.ResponseWriter, req *http.Request) { - spanCtx, err := e.Extract(opentracing.HTTPHeaders, opentracing.HTTPHeadersCarrier(req.Header)) - if err != nil { - middlewares.GetLogger(req.Context(), "tracing", entryPointTypeName). - Debug().Err(err).Msg("Failed to extract the context") +// WrapEntryPointHandler Wraps tracing to alice.Constructor. +func WrapEntryPointHandler(ctx context.Context, tracer trace.Tracer, entryPointName string) alice.Constructor { + return func(next http.Handler) (http.Handler, error) { + return newEntryPoint(ctx, tracer, entryPointName, next), nil } +} - span, req, finish := e.StartSpanf(req, ext.SpanKindRPCServerEnum, "EntryPoint", []string{e.entryPoint, req.Host}, " ", ext.RPCServerOption(spanCtx)) - defer finish() +// newEntryPoint creates a new tracing middleware for incoming requests. +func newEntryPoint(ctx context.Context, tracer trace.Tracer, entryPointName string, next http.Handler) http.Handler { + middlewares.GetLogger(ctx, "tracing", entryPointTypeName).Debug().Msg("Creating middleware") - ext.Component.Set(span, e.ServiceName) - tracing.LogRequest(span, req) + return &entryPointTracing{ + entryPoint: entryPointName, + tracer: tracer, + next: next, + } +} - req = req.WithContext(tracing.WithTracing(req.Context(), e.Tracing)) +func (e *entryPointTracing) ServeHTTP(rw http.ResponseWriter, req *http.Request) { + tracingCtx := tracing.ExtractCarrierIntoContext(req.Context(), req.Header) + tracingCtx, span := e.tracer.Start(tracingCtx, "EntryPoint", trace.WithSpanKind(trace.SpanKindServer)) + defer span.End() + + req = req.WithContext(tracingCtx) + + span.SetAttributes(attribute.String("entry_point", e.entryPoint)) + + tracing.LogServerRequest(span, req) recorder := newStatusCodeRecorder(rw, http.StatusOK) e.next.ServeHTTP(recorder, req) - tracing.LogResponseCode(span, recorder.Status()) -} - -// WrapEntryPointHandler Wraps tracing to alice.Constructor. -func WrapEntryPointHandler(ctx context.Context, tracer *tracing.Tracing, entryPointName string) alice.Constructor { - return func(next http.Handler) (http.Handler, error) { - return NewEntryPoint(ctx, tracer, entryPointName, next), nil - } + tracing.LogResponseCode(span, recorder.Status(), trace.SpanKindServer) } diff --git a/pkg/middlewares/tracing/entrypoint_test.go b/pkg/middlewares/tracing/entrypoint_test.go index e8528e048..b3cb60d67 100644 --- a/pkg/middlewares/tracing/entrypoint_test.go +++ b/pkg/middlewares/tracing/entrypoint_test.go @@ -6,81 +6,69 @@ import ( "net/http/httptest" "testing" - "github.com/opentracing/opentracing-go/ext" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/traefik/traefik/v3/pkg/tracing" + "go.opentelemetry.io/otel/attribute" ) func TestEntryPointMiddleware(t *testing.T) { type expected struct { - Tags map[string]interface{} - OperationName string + name string + attributes []attribute.KeyValue } testCases := []struct { - desc string - entryPoint string - spanNameLimit int - tracing *trackingBackenMock - expected expected + desc string + entryPoint string + expected expected }{ { - desc: "no truncation test", - entryPoint: "test", - spanNameLimit: 0, - tracing: &trackingBackenMock{ - tracer: &MockTracer{Span: &MockSpan{Tags: make(map[string]interface{})}}, - }, + desc: "basic test", + entryPoint: "test", expected: expected{ - Tags: map[string]interface{}{ - "span.kind": ext.SpanKindRPCServerEnum, - "http.method": http.MethodGet, - "component": "", - "http.url": "http://www.test.com", - "http.host": "www.test.com", + name: "EntryPoint", + attributes: []attribute.KeyValue{ + attribute.String("span.kind", "server"), + attribute.String("entry_point", "test"), + attribute.String("http.request.method", "GET"), + attribute.String("network.protocol.version", "1.1"), + attribute.Int64("http.request.body.size", int64(0)), + attribute.String("url.path", "/search"), + attribute.String("url.query", "q=Opentelemetry"), + attribute.String("url.scheme", "http"), + attribute.String("user_agent.original", "entrypoint-test"), + attribute.String("server.address", "www.test.com"), + attribute.String("network.peer.address", "10.0.0.1"), + attribute.String("network.peer.port", "1234"), + attribute.String("client.address", "10.0.0.1"), + attribute.Int64("client.port", int64(1234)), + attribute.String("client.socket.address", ""), + attribute.Int64("http.response.status_code", int64(404)), }, - OperationName: "EntryPoint test www.test.com", - }, - }, - { - desc: "basic test", - entryPoint: "test", - spanNameLimit: 25, - tracing: &trackingBackenMock{ - tracer: &MockTracer{Span: &MockSpan{Tags: make(map[string]interface{})}}, - }, - expected: expected{ - Tags: map[string]interface{}{ - "span.kind": ext.SpanKindRPCServerEnum, - "http.method": http.MethodGet, - "component": "", - "http.url": "http://www.test.com", - "http.host": "www.test.com", - }, - OperationName: "EntryPoint te... ww... 0c15301b", }, }, } for _, test := range testCases { t.Run(test.desc, func(t *testing.T) { - newTracing, err := tracing.NewTracing("", test.spanNameLimit, test.tracing) - require.NoError(t, err) - - req := httptest.NewRequest(http.MethodGet, "http://www.test.com", nil) + req := httptest.NewRequest(http.MethodGet, "http://www.test.com/search?q=Opentelemetry", nil) rw := httptest.NewRecorder() + req.RemoteAddr = "10.0.0.1:1234" + req.Header.Set("User-Agent", "entrypoint-test") + req.Header.Set("X-Forwarded-Proto", "http") - next := http.HandlerFunc(func(http.ResponseWriter, *http.Request) { - span := test.tracing.tracer.(*MockTracer).Span - - tags := span.Tags - assert.Equal(t, test.expected.Tags, tags) - assert.Equal(t, test.expected.OperationName, span.OpName) + next := http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) { + rw.WriteHeader(http.StatusNotFound) }) - handler := NewEntryPoint(context.Background(), newTracing, test.entryPoint, next) + tracer := &mockTracer{} + + handler := newEntryPoint(context.Background(), tracer, test.entryPoint, next) handler.ServeHTTP(rw, req) + + for _, span := range tracer.spans { + assert.Equal(t, test.expected.name, span.name) + assert.Equal(t, test.expected.attributes, span.attributes) + } }) } } diff --git a/pkg/middlewares/tracing/forwarder.go b/pkg/middlewares/tracing/forwarder.go deleted file mode 100644 index e2ee76a10..000000000 --- a/pkg/middlewares/tracing/forwarder.go +++ /dev/null @@ -1,59 +0,0 @@ -package tracing - -import ( - "context" - "net/http" - - "github.com/opentracing/opentracing-go/ext" - "github.com/traefik/traefik/v3/pkg/logs" - "github.com/traefik/traefik/v3/pkg/middlewares" - "github.com/traefik/traefik/v3/pkg/tracing" -) - -const ( - forwarderTypeName = "TracingForwarder" -) - -type forwarderMiddleware struct { - router string - service string - next http.Handler -} - -// NewForwarder creates a new forwarder middleware that traces the outgoing request. -func NewForwarder(ctx context.Context, router, service string, next http.Handler) http.Handler { - middlewares.GetLogger(ctx, "tracing", forwarderTypeName). - Debug().Str(logs.ServiceName, service).Msg("Added outgoing tracing middleware") - - return &forwarderMiddleware{ - router: router, - service: service, - next: next, - } -} - -func (f *forwarderMiddleware) ServeHTTP(rw http.ResponseWriter, req *http.Request) { - tr, err := tracing.FromContext(req.Context()) - if err != nil { - f.next.ServeHTTP(rw, req) - return - } - - opParts := []string{f.service, f.router} - span, req, finish := tr.StartSpanf(req, ext.SpanKindRPCClientEnum, "forward", opParts, "/") - defer finish() - - span.SetTag("traefik.service.name", f.service) - span.SetTag("traefik.router.name", f.router) - ext.HTTPMethod.Set(span, req.Method) - ext.HTTPUrl.Set(span, req.URL.String()) - span.SetTag("http.host", req.Host) - - tracing.InjectRequestHeaders(req) - - recorder := newStatusCodeRecorder(rw, 200) - - f.next.ServeHTTP(recorder, req) - - tracing.LogResponseCode(span, recorder.Status()) -} diff --git a/pkg/middlewares/tracing/forwarder_test.go b/pkg/middlewares/tracing/forwarder_test.go deleted file mode 100644 index e56c47502..000000000 --- a/pkg/middlewares/tracing/forwarder_test.go +++ /dev/null @@ -1,136 +0,0 @@ -package tracing - -import ( - "context" - "net/http" - "net/http/httptest" - "testing" - - "github.com/opentracing/opentracing-go/ext" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/traefik/traefik/v3/pkg/tracing" -) - -func TestNewForwarder(t *testing.T) { - type expected struct { - Tags map[string]interface{} - OperationName string - } - - testCases := []struct { - desc string - spanNameLimit int - tracing *trackingBackenMock - service string - router string - expected expected - }{ - { - desc: "Simple Forward Tracer without truncation and hashing", - spanNameLimit: 101, - tracing: &trackingBackenMock{ - tracer: &MockTracer{Span: &MockSpan{Tags: make(map[string]interface{})}}, - }, - service: "some-service.domain.tld", - router: "some-service.domain.tld", - expected: expected{ - Tags: map[string]interface{}{ - "http.host": "www.test.com", - "http.method": "GET", - "http.url": "http://www.test.com/toto", - "traefik.service.name": "some-service.domain.tld", - "traefik.router.name": "some-service.domain.tld", - "span.kind": ext.SpanKindRPCClientEnum, - }, - OperationName: "forward some-service.domain.tld/some-service.domain.tld", - }, - }, - { - desc: "Simple Forward Tracer with truncation and hashing", - spanNameLimit: 101, - tracing: &trackingBackenMock{ - tracer: &MockTracer{Span: &MockSpan{Tags: make(map[string]interface{})}}, - }, - service: "some-service-100.slug.namespace.environment.domain.tld", - router: "some-service-100.slug.namespace.environment.domain.tld", - expected: expected{ - Tags: map[string]interface{}{ - "http.host": "www.test.com", - "http.method": "GET", - "http.url": "http://www.test.com/toto", - "traefik.service.name": "some-service-100.slug.namespace.environment.domain.tld", - "traefik.router.name": "some-service-100.slug.namespace.environment.domain.tld", - "span.kind": ext.SpanKindRPCClientEnum, - }, - OperationName: "forward some-service-100.slug.namespace.enviro.../some-service-100.slug.namespace.enviro.../bc4a0d48", - }, - }, - { - desc: "Exactly 101 chars", - spanNameLimit: 101, - tracing: &trackingBackenMock{ - tracer: &MockTracer{Span: &MockSpan{Tags: make(map[string]interface{})}}, - }, - service: "some-service1.namespace.environment.domain.tld", - router: "some-service1.namespace.environment.domain.tld", - expected: expected{ - Tags: map[string]interface{}{ - "http.host": "www.test.com", - "http.method": "GET", - "http.url": "http://www.test.com/toto", - "traefik.service.name": "some-service1.namespace.environment.domain.tld", - "traefik.router.name": "some-service1.namespace.environment.domain.tld", - "span.kind": ext.SpanKindRPCClientEnum, - }, - OperationName: "forward some-service1.namespace.environment.domain.tld/some-service1.namespace.environment.domain.tld", - }, - }, - { - desc: "More than 101 chars", - spanNameLimit: 101, - tracing: &trackingBackenMock{ - tracer: &MockTracer{Span: &MockSpan{Tags: make(map[string]interface{})}}, - }, - service: "some-service1.frontend.namespace.environment.domain.tld", - router: "some-service1.backend.namespace.environment.domain.tld", - expected: expected{ - Tags: map[string]interface{}{ - "http.host": "www.test.com", - "http.method": "GET", - "http.url": "http://www.test.com/toto", - "traefik.service.name": "some-service1.frontend.namespace.environment.domain.tld", - "traefik.router.name": "some-service1.backend.namespace.environment.domain.tld", - "span.kind": ext.SpanKindRPCClientEnum, - }, - OperationName: "forward some-service1.frontend.namespace.envir.../some-service1.backend.namespace.enviro.../fa49dd23", - }, - }, - } - - for _, test := range testCases { - t.Run(test.desc, func(t *testing.T) { - newTracing, err := tracing.NewTracing("", test.spanNameLimit, test.tracing) - require.NoError(t, err) - - req := httptest.NewRequest(http.MethodGet, "http://www.test.com/toto", nil) - req = req.WithContext(tracing.WithTracing(req.Context(), newTracing)) - - rw := httptest.NewRecorder() - - next := http.HandlerFunc(func(http.ResponseWriter, *http.Request) { - span := test.tracing.tracer.(*MockTracer).Span - - tags := span.Tags - assert.Equal(t, test.expected.Tags, tags) - assert.LessOrEqual(t, len(test.expected.OperationName), test.spanNameLimit, - "the len of the operation name %q [len: %d] doesn't respect limit %d", - test.expected.OperationName, len(test.expected.OperationName), test.spanNameLimit) - assert.Equal(t, test.expected.OperationName, span.OpName) - }) - - handler := NewForwarder(context.Background(), test.router, test.service, next) - handler.ServeHTTP(rw, req) - }) - } -} diff --git a/pkg/middlewares/tracing/middleware.go b/pkg/middlewares/tracing/middleware.go new file mode 100644 index 000000000..47a6af502 --- /dev/null +++ b/pkg/middlewares/tracing/middleware.go @@ -0,0 +1,71 @@ +package tracing + +import ( + "context" + "net/http" + + "github.com/containous/alice" + "github.com/rs/zerolog/log" + "github.com/traefik/traefik/v3/pkg/logs" + "github.com/traefik/traefik/v3/pkg/tracing" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" +) + +// Traceable embeds tracing information. +type Traceable interface { + GetTracingInformation() (name string, typeName string, spanKind trace.SpanKind) +} + +// WrapMiddleware adds traceability to an alice.Constructor. +func WrapMiddleware(ctx context.Context, constructor alice.Constructor) alice.Constructor { + return func(next http.Handler) (http.Handler, error) { + if constructor == nil { + return nil, nil + } + handler, err := constructor(next) + if err != nil { + return nil, err + } + + if traceableHandler, ok := handler.(Traceable); ok { + name, typeName, spanKind := traceableHandler.GetTracingInformation() + log.Ctx(ctx).Debug().Str(logs.MiddlewareName, name).Msg("Adding tracing to middleware") + return NewMiddleware(handler, name, typeName, spanKind), nil + } + return handler, nil + } +} + +// NewMiddleware returns a http.Handler struct. +func NewMiddleware(next http.Handler, name string, typeName string, spanKind trace.SpanKind) http.Handler { + return &middlewareTracing{ + next: next, + name: name, + typeName: typeName, + spanKind: spanKind, + } +} + +// middlewareTracing is used to wrap http handler middleware. +type middlewareTracing struct { + next http.Handler + name string + typeName string + spanKind trace.SpanKind +} + +func (w *middlewareTracing) ServeHTTP(rw http.ResponseWriter, req *http.Request) { + if tracer := tracing.TracerFromContext(req.Context()); tracer != nil { + tracingCtx, span := tracer.Start(req.Context(), w.typeName, trace.WithSpanKind(w.spanKind)) + defer span.End() + + req = req.WithContext(tracingCtx) + + span.SetAttributes(attribute.String("traefik.middleware.name", w.name)) + } + + if w.next != nil { + w.next.ServeHTTP(rw, req) + } +} diff --git a/pkg/middlewares/tracing/mock_tracing_test.go b/pkg/middlewares/tracing/mock_tracing_test.go index 33aac1ee6..a44345f6a 100644 --- a/pkg/middlewares/tracing/mock_tracing_test.go +++ b/pkg/middlewares/tracing/mock_tracing_test.go @@ -1,70 +1,62 @@ package tracing import ( - "io" + "context" - "github.com/opentracing/opentracing-go" - "github.com/opentracing/opentracing-go/log" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/codes" + "go.opentelemetry.io/otel/trace" + "go.opentelemetry.io/otel/trace/embedded" ) -type MockTracer struct { - Span *MockSpan +type mockTracerProvider struct { + embedded.TracerProvider } -// StartSpan belongs to the Tracer interface. -func (n MockTracer) StartSpan(operationName string, opts ...opentracing.StartSpanOption) opentracing.Span { - n.Span.OpName = operationName - return n.Span +var _ trace.TracerProvider = mockTracerProvider{} + +func (p mockTracerProvider) Tracer(string, ...trace.TracerOption) trace.Tracer { + return &mockTracer{} } -// Inject belongs to the Tracer interface. -func (n MockTracer) Inject(sp opentracing.SpanContext, format, carrier interface{}) error { - return nil +type mockTracer struct { + embedded.Tracer + + spans []*mockSpan } -// Extract belongs to the Tracer interface. -func (n MockTracer) Extract(format, carrier interface{}) (opentracing.SpanContext, error) { - return nil, opentracing.ErrSpanContextNotFound +var _ trace.Tracer = &mockTracer{} + +func (t *mockTracer) Start(ctx context.Context, name string, opts ...trace.SpanStartOption) (context.Context, trace.Span) { + config := trace.NewSpanStartConfig(opts...) + span := &mockSpan{} + span.SetName(name) + span.SetAttributes(attribute.String("span.kind", config.SpanKind().String())) + span.SetAttributes(config.Attributes()...) + t.spans = append(t.spans, span) + return trace.ContextWithSpan(ctx, span), span } -// MockSpanContext a span context mock. -type MockSpanContext struct{} +// mockSpan is an implementation of Span that preforms no operations. +type mockSpan struct { + embedded.Span -func (n MockSpanContext) ForeachBaggageItem(handler func(k, v string) bool) {} - -// MockSpan a span mock. -type MockSpan struct { - OpName string - Tags map[string]interface{} + name string + attributes []attribute.KeyValue } -func (n MockSpan) Context() opentracing.SpanContext { return MockSpanContext{} } -func (n MockSpan) SetBaggageItem(key, val string) opentracing.Span { - return MockSpan{Tags: make(map[string]interface{})} -} -func (n MockSpan) BaggageItem(key string) string { return "" } -func (n MockSpan) SetTag(key string, value interface{}) opentracing.Span { - n.Tags[key] = value - return n -} -func (n MockSpan) LogFields(fields ...log.Field) {} -func (n MockSpan) LogKV(keyVals ...interface{}) {} -func (n MockSpan) Finish() {} -func (n MockSpan) FinishWithOptions(opts opentracing.FinishOptions) {} -func (n MockSpan) SetOperationName(operationName string) opentracing.Span { return n } -func (n MockSpan) Tracer() opentracing.Tracer { return MockTracer{} } -func (n MockSpan) LogEvent(event string) {} -func (n MockSpan) LogEventWithPayload(event string, payload interface{}) {} -func (n MockSpan) Log(data opentracing.LogData) {} -func (n *MockSpan) Reset() { - n.Tags = make(map[string]interface{}) -} +var _ trace.Span = &mockSpan{} -type trackingBackenMock struct { - tracer opentracing.Tracer +func (*mockSpan) SpanContext() trace.SpanContext { return trace.SpanContext{} } +func (*mockSpan) IsRecording() bool { return false } +func (s *mockSpan) SetStatus(_ codes.Code, _ string) {} +func (s *mockSpan) SetAttributes(kv ...attribute.KeyValue) { + s.attributes = append(s.attributes, kv...) } +func (s *mockSpan) End(...trace.SpanEndOption) {} +func (s *mockSpan) RecordError(_ error, _ ...trace.EventOption) {} +func (s *mockSpan) AddEvent(_ string, _ ...trace.EventOption) {} -func (t *trackingBackenMock) Setup(componentName string) (opentracing.Tracer, io.Closer, error) { - opentracing.SetGlobalTracer(t.tracer) - return t.tracer, nil, nil -} +func (s *mockSpan) SetName(name string) { s.name = name } + +func (*mockSpan) TracerProvider() trace.TracerProvider { return mockTracerProvider{} } diff --git a/pkg/middlewares/tracing/router.go b/pkg/middlewares/tracing/router.go new file mode 100644 index 000000000..e964be12c --- /dev/null +++ b/pkg/middlewares/tracing/router.go @@ -0,0 +1,60 @@ +package tracing + +import ( + "context" + "net/http" + + "github.com/containous/alice" + "github.com/traefik/traefik/v3/pkg/logs" + "github.com/traefik/traefik/v3/pkg/middlewares" + "github.com/traefik/traefik/v3/pkg/tracing" + "go.opentelemetry.io/otel/attribute" + semconv "go.opentelemetry.io/otel/semconv/v1.21.0" + "go.opentelemetry.io/otel/trace" +) + +const ( + routerTypeName = "TracingRouter" +) + +type routerTracing struct { + router string + routerRule string + service string + next http.Handler +} + +// WrapRouterHandler Wraps tracing to alice.Constructor. +func WrapRouterHandler(ctx context.Context, router, routerRule, service string) alice.Constructor { + return func(next http.Handler) (http.Handler, error) { + return newRouter(ctx, router, routerRule, service, next), nil + } +} + +// newRouter creates a new tracing middleware that traces the internal requests. +func newRouter(ctx context.Context, router, routerRule, service string, next http.Handler) http.Handler { + middlewares.GetLogger(ctx, "tracing", routerTypeName). + Debug().Str(logs.RouterName, router).Str(logs.ServiceName, service).Msg("Added outgoing tracing middleware") + + return &routerTracing{ + router: router, + routerRule: routerRule, + service: service, + next: next, + } +} + +func (f *routerTracing) ServeHTTP(rw http.ResponseWriter, req *http.Request) { + if tracer := tracing.TracerFromContext(req.Context()); tracer != nil { + tracingCtx, span := tracer.Start(req.Context(), "Router", trace.WithSpanKind(trace.SpanKindInternal)) + defer span.End() + + req = req.WithContext(tracingCtx) + + span.SetAttributes(attribute.String("traefik.service.name", f.service)) + span.SetAttributes(attribute.String("traefik.router.name", f.router)) + span.SetAttributes(semconv.HTTPRoute(f.routerRule)) + } + + f.next.ServeHTTP(rw, req) +} diff --git a/pkg/middlewares/tracing/router_test.go b/pkg/middlewares/tracing/router_test.go new file mode 100644 index 000000000..b220cdabe --- /dev/null +++ b/pkg/middlewares/tracing/router_test.go @@ -0,0 +1,86 @@ +package tracing + +import ( + "context" + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/assert" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" +) + +func TestNewRouter(t *testing.T) { + type expected struct { + attributes []attribute.KeyValue + name string + } + + testCases := []struct { + desc string + service string + router string + routerRule string + expected []expected + }{ + { + desc: "base", + service: "myService", + router: "myRouter", + routerRule: "Path(`/`)", + expected: []expected{ + { + name: "EntryPoint", + attributes: []attribute.KeyValue{ + attribute.String("span.kind", "server"), + }, + }, + { + name: "Router", + attributes: []attribute.KeyValue{ + attribute.String("span.kind", "internal"), + attribute.String("http.request.method", "GET"), + attribute.Int64("http.response.status_code", int64(404)), + attribute.String("network.protocol.version", "1.1"), + attribute.String("server.address", "www.test.com"), + attribute.Int64("server.port", int64(80)), + attribute.String("url.full", "http://www.test.com/traces?p=OpenTelemetry"), + attribute.String("url.scheme", "http"), + attribute.String("traefik.service.name", "myService"), + attribute.String("traefik.router.name", "myRouter"), + attribute.String("http.route", "Path(`/`)"), + attribute.String("user_agent.original", "router-test"), + }, + }, + }, + }, + } + + for _, test := range testCases { + t.Run(test.desc, func(t *testing.T) { + req := httptest.NewRequest(http.MethodGet, "http://www.test.com/traces?p=OpenTelemetry", nil) + req.RemoteAddr = "10.0.0.1:1234" + req.Header.Set("User-Agent", "router-test") + + tracer := &mockTracer{} + tracingCtx, entryPointSpan := tracer.Start(req.Context(), "EntryPoint", trace.WithSpanKind(trace.SpanKindServer)) + defer entryPointSpan.End() + + req = req.WithContext(tracingCtx) + + rw := httptest.NewRecorder() + next := http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) { + rw.WriteHeader(http.StatusNotFound) + }) + + handler := newRouter(context.Background(), test.router, test.routerRule, test.service, next) + handler.ServeHTTP(rw, req) + + for i, span := range tracer.spans { + assert.Equal(t, test.expected[i].name, span.name) + assert.Equal(t, test.expected[i].attributes, span.attributes) + } + }) + } +} diff --git a/pkg/middlewares/tracing/service.go b/pkg/middlewares/tracing/service.go new file mode 100644 index 000000000..9cc5bd1ca --- /dev/null +++ b/pkg/middlewares/tracing/service.go @@ -0,0 +1,45 @@ +package tracing + +import ( + "context" + "net/http" + + "github.com/traefik/traefik/v3/pkg/logs" + "github.com/traefik/traefik/v3/pkg/middlewares" + "github.com/traefik/traefik/v3/pkg/tracing" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" +) + +const ( + serviceTypeName = "TracingService" +) + +type serviceTracing struct { + service string + next http.Handler +} + +// NewService creates a new tracing middleware that traces the outgoing requests. +func NewService(ctx context.Context, service string, next http.Handler) http.Handler { + middlewares.GetLogger(ctx, "tracing", serviceTypeName). + Debug().Str(logs.ServiceName, service).Msg("Added outgoing tracing middleware") + + return &serviceTracing{ + service: service, + next: next, + } +} + +func (t *serviceTracing) ServeHTTP(rw http.ResponseWriter, req *http.Request) { + if tracer := tracing.TracerFromContext(req.Context()); tracer != nil { + tracingCtx, span := tracer.Start(req.Context(), "Service", trace.WithSpanKind(trace.SpanKindInternal)) + defer span.End() + + req = req.WithContext(tracingCtx) + + span.SetAttributes(attribute.String("traefik.service.name", t.service)) + } + + t.next.ServeHTTP(rw, req) +} diff --git a/pkg/middlewares/tracing/service_test.go b/pkg/middlewares/tracing/service_test.go new file mode 100644 index 000000000..c78510faf --- /dev/null +++ b/pkg/middlewares/tracing/service_test.go @@ -0,0 +1,80 @@ +package tracing + +import ( + "context" + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/assert" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" +) + +func TestNewService(t *testing.T) { + type expected struct { + attributes []attribute.KeyValue + name string + } + + testCases := []struct { + desc string + service string + expected []expected + }{ + { + desc: "base", + service: "myService", + expected: []expected{ + { + name: "EntryPoint", + attributes: []attribute.KeyValue{ + attribute.String("span.kind", "server"), + }, + }, + { + name: "Service", + attributes: []attribute.KeyValue{ + attribute.String("span.kind", "internal"), + attribute.String("http.request.method", "GET"), + attribute.Int64("http.response.status_code", int64(404)), + attribute.String("network.protocol.version", "1.1"), + attribute.String("server.address", "www.test.com"), + attribute.Int64("server.port", int64(80)), + attribute.String("url.full", "http://www.test.com/traces?p=OpenTelemetry"), + attribute.String("url.scheme", "http"), + attribute.String("traefik.service.name", "myService"), + attribute.String("user_agent.original", "service-test"), + }, + }, + }, + }, + } + + for _, test := range testCases { + t.Run(test.desc, func(t *testing.T) { + req := httptest.NewRequest(http.MethodGet, "http://www.test.com/traces?p=OpenTelemetry", nil) + req.RemoteAddr = "10.0.0.1:1234" + req.Header.Set("User-Agent", "service-test") + + tracer := &mockTracer{} + tracingCtx, entryPointSpan := tracer.Start(req.Context(), "EntryPoint", trace.WithSpanKind(trace.SpanKindServer)) + defer entryPointSpan.End() + + req = req.WithContext(tracingCtx) + + rw := httptest.NewRecorder() + next := http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) { + rw.WriteHeader(http.StatusNotFound) + }) + + handler := NewService(context.Background(), test.service, next) + handler.ServeHTTP(rw, req) + + for i, span := range tracer.spans { + assert.Equal(t, test.expected[i].name, span.name) + assert.Equal(t, test.expected[i].attributes, span.attributes) + } + }) + } +} diff --git a/pkg/middlewares/tracing/wrapper.go b/pkg/middlewares/tracing/wrapper.go deleted file mode 100644 index 1fa3cfcdd..000000000 --- a/pkg/middlewares/tracing/wrapper.go +++ /dev/null @@ -1,69 +0,0 @@ -package tracing - -import ( - "context" - "net/http" - - "github.com/containous/alice" - "github.com/opentracing/opentracing-go/ext" - "github.com/rs/zerolog/log" - "github.com/traefik/traefik/v3/pkg/logs" - "github.com/traefik/traefik/v3/pkg/tracing" -) - -// Traceable embeds tracing information. -type Traceable interface { - GetTracingInformation() (name string, spanKind ext.SpanKindEnum) -} - -// Wrap adds traceability to an alice.Constructor. -func Wrap(ctx context.Context, constructor alice.Constructor) alice.Constructor { - return func(next http.Handler) (http.Handler, error) { - if constructor == nil { - return nil, nil - } - handler, err := constructor(next) - if err != nil { - return nil, err - } - - if traceableHandler, ok := handler.(Traceable); ok { - name, spanKind := traceableHandler.GetTracingInformation() - log.Ctx(ctx).Debug().Str(logs.MiddlewareName, name).Msg("Adding tracing to middleware") - return NewWrapper(handler, name, spanKind), nil - } - return handler, nil - } -} - -// NewWrapper returns a http.Handler struct. -func NewWrapper(next http.Handler, name string, spanKind ext.SpanKindEnum) http.Handler { - return &Wrapper{ - next: next, - name: name, - spanKind: spanKind, - } -} - -// Wrapper is used to wrap http handler middleware. -type Wrapper struct { - next http.Handler - name string - spanKind ext.SpanKindEnum -} - -func (w *Wrapper) ServeHTTP(rw http.ResponseWriter, req *http.Request) { - _, err := tracing.FromContext(req.Context()) - if err != nil { - w.next.ServeHTTP(rw, req) - return - } - - var finish func() - _, req, finish = tracing.StartSpan(req, w.name, w.spanKind) - defer finish() - - if w.next != nil { - w.next.ServeHTTP(rw, req) - } -} diff --git a/pkg/redactor/redactor_config_test.go b/pkg/redactor/redactor_config_test.go index f785ec72d..0a6b174e9 100644 --- a/pkg/redactor/redactor_config_test.go +++ b/pkg/redactor/redactor_config_test.go @@ -30,12 +30,7 @@ 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/datadog" - "github.com/traefik/traefik/v3/pkg/tracing/elastic" - "github.com/traefik/traefik/v3/pkg/tracing/haystack" - "github.com/traefik/traefik/v3/pkg/tracing/instana" - "github.com/traefik/traefik/v3/pkg/tracing/jaeger" - "github.com/traefik/traefik/v3/pkg/tracing/zipkin" + "github.com/traefik/traefik/v3/pkg/tracing/opentelemetry" "github.com/traefik/traefik/v3/pkg/types" ) @@ -850,58 +845,19 @@ func TestDo_staticConfiguration(t *testing.T) { } config.Tracing = &static.Tracing{ - ServiceName: "myServiceName", - SpanNameLimit: 42, - Jaeger: &jaeger.Config{ - SamplingServerURL: "foobar", - SamplingType: "foobar", - SamplingParam: 42, - LocalAgentHostPort: "foobar", - Gen128Bit: true, - Propagation: "foobar", - TraceContextHeaderName: "foobar", - Collector: &jaeger.Collector{ + ServiceName: "myServiceName", + Headers: map[string]string{ + "foobar": "foobar", + }, + GlobalAttributes: map[string]string{ + "foobar": "foobar", + }, + SampleRate: 42, + OTLP: &opentelemetry.Config{ + HTTP: &opentelemetry.HTTP{ Endpoint: "foobar", - User: "foobar", - Password: "foobar", + TLS: nil, }, - DisableAttemptReconnecting: true, - }, - Zipkin: &zipkin.Config{ - HTTPEndpoint: "foobar", - SameSpan: true, - ID128Bit: true, - SampleRate: 42, - }, - Datadog: &datadog.Config{ - LocalAgentHostPort: "foobar", - LocalAgentSocket: "foobar", - GlobalTags: map[string]string{"foobar": "foobar"}, - Debug: true, - PrioritySampling: true, - TraceIDHeaderName: "foobar", - ParentIDHeaderName: "foobar", - SamplingPriorityHeaderName: "foobar", - BagagePrefixHeaderName: "foobar", - }, - Instana: &instana.Config{ - LocalAgentHost: "foobar", - LocalAgentPort: 4242, - LogLevel: "foobar", - }, - Haystack: &haystack.Config{ - LocalAgentHost: "foobar", - LocalAgentPort: 42, - GlobalTag: "foobar", - TraceIDHeaderName: "foobar", - ParentIDHeaderName: "foobar", - SpanIDHeaderName: "foobar", - BaggagePrefixHeaderName: "foobar", - }, - Elastic: &elastic.Config{ - ServerURL: "foobar", - SecretToken: "foobar", - ServiceEnvironment: "foobar", }, } diff --git a/pkg/redactor/testdata/anonymized-static-config.json b/pkg/redactor/testdata/anonymized-static-config.json index a8db72460..97e678c85 100644 --- a/pkg/redactor/testdata/anonymized-static-config.json +++ b/pkg/redactor/testdata/anonymized-static-config.json @@ -344,57 +344,17 @@ }, "tracing": { "serviceName": "myServiceName", - "spanNameLimit": 42, - "jaeger": { - "samplingServerURL": "xxxx", - "samplingType": "foobar", - "samplingParam": 42, - "localAgentHostPort": "xxxx", - "gen128Bit": true, - "propagation": "foobar", - "traceContextHeaderName": "foobar", - "collector": { - "endpoint": "xxxx", - "user": "xxxx", - "password": "xxxx" - }, - "disableAttemptReconnecting": true + "headers": { + "foobar": "foobar" }, - "zipkin": { - "httpEndpoint": "xxxx", - "sameSpan": true, - "id128Bit": true, - "sampleRate": 42 + "globalAttributes": { + "foobar": "foobar" }, - "datadog": { - "localAgentHostPort": "xxxx", - "localAgentSocket": "xxxx", - "globalTags": { - "foobar": "foobar" - }, - "debug": true, - "prioritySampling": true, - "traceIDHeaderName": "foobar", - "parentIDHeaderName": "foobar", - "samplingPriorityHeaderName": "foobar", - "bagagePrefixHeaderName": "foobar" - }, - "instana": { - "localAgentHost": "xxxx", - "logLevel": "foobar" - }, - "haystack": { - "localAgentHost": "xxxx", - "globalTag": "foobar", - "traceIDHeaderName": "foobar", - "parentIDHeaderName": "foobar", - "spanIDHeaderName": "foobar", - "baggagePrefixHeaderName": "foobar" - }, - "elastic": { - "serverURL": "xxxx", - "secretToken": "xxxx", - "serviceEnvironment": "foobar" + "sampleRate": 42, + "otlp": { + "http": { + "endpoint": "xxxx" + } } }, "hostResolver": { @@ -447,4 +407,4 @@ } } } -} \ No newline at end of file +} diff --git a/pkg/server/middleware/chainbuilder.go b/pkg/server/middleware/chainbuilder.go index 864e7e68b..980d7a2b5 100644 --- a/pkg/server/middleware/chainbuilder.go +++ b/pkg/server/middleware/chainbuilder.go @@ -8,20 +8,20 @@ import ( "github.com/traefik/traefik/v3/pkg/metrics" "github.com/traefik/traefik/v3/pkg/middlewares/accesslog" "github.com/traefik/traefik/v3/pkg/middlewares/capture" - metricsmiddleware "github.com/traefik/traefik/v3/pkg/middlewares/metrics" - mTracing "github.com/traefik/traefik/v3/pkg/middlewares/tracing" - "github.com/traefik/traefik/v3/pkg/tracing" + metricsMiddle "github.com/traefik/traefik/v3/pkg/middlewares/metrics" + tracingMiddle "github.com/traefik/traefik/v3/pkg/middlewares/tracing" + "go.opentelemetry.io/otel/trace" ) // ChainBuilder Creates a middleware chain by entry point. It is used for middlewares that are created almost systematically and that need to be created before all others. type ChainBuilder struct { metricsRegistry metrics.Registry accessLoggerMiddleware *accesslog.Handler - tracer *tracing.Tracing + tracer trace.Tracer } // NewChainBuilder Creates a new ChainBuilder. -func NewChainBuilder(metricsRegistry metrics.Registry, accessLoggerMiddleware *accesslog.Handler, tracer *tracing.Tracing) *ChainBuilder { +func NewChainBuilder(metricsRegistry metrics.Registry, accessLoggerMiddleware *accesslog.Handler, tracer trace.Tracer) *ChainBuilder { return &ChainBuilder{ metricsRegistry: metricsRegistry, accessLoggerMiddleware: accessLoggerMiddleware, @@ -42,11 +42,12 @@ func (c *ChainBuilder) Build(ctx context.Context, entryPointName string) alice.C } if c.tracer != nil { - chain = chain.Append(mTracing.WrapEntryPointHandler(ctx, c.tracer, entryPointName)) + chain = chain.Append(tracingMiddle.WrapEntryPointHandler(ctx, c.tracer, entryPointName)) } if c.metricsRegistry != nil && c.metricsRegistry.IsEpEnabled() { - chain = chain.Append(metricsmiddleware.WrapEntryPointHandler(ctx, c.metricsRegistry, entryPointName)) + metricsHandler := metricsMiddle.WrapEntryPointHandler(ctx, c.metricsRegistry, entryPointName) + chain = chain.Append(tracingMiddle.WrapMiddleware(ctx, metricsHandler)) } return chain @@ -59,8 +60,4 @@ func (c *ChainBuilder) Close() { log.Error().Err(err).Msg("Could not close the access log file") } } - - if c.tracer != nil { - c.tracer.Close() - } } diff --git a/pkg/server/middleware/middlewares.go b/pkg/server/middleware/middlewares.go index afeab88e4..fe2fd23a9 100644 --- a/pkg/server/middleware/middlewares.go +++ b/pkg/server/middleware/middlewares.go @@ -372,7 +372,7 @@ func (b *Builder) buildConstructor(ctx context.Context, middlewareName string) ( return nil, fmt.Errorf("invalid middleware %q configuration: invalid middleware type or middleware does not exist", middlewareName) } - return tracing.Wrap(ctx, middleware), nil + return tracing.WrapMiddleware(ctx, middleware), nil } func inSlice(element string, stack []string) bool { diff --git a/pkg/server/middleware/plugins.go b/pkg/server/middleware/plugins.go index 80253b05b..eacf8fba1 100644 --- a/pkg/server/middleware/plugins.go +++ b/pkg/server/middleware/plugins.go @@ -5,12 +5,13 @@ import ( "errors" "net/http" - "github.com/opentracing/opentracing-go/ext" "github.com/traefik/traefik/v3/pkg/config/dynamic" "github.com/traefik/traefik/v3/pkg/plugins" - "github.com/traefik/traefik/v3/pkg/tracing" + "go.opentelemetry.io/otel/trace" ) +const typeName = "Plugin" + // PluginsBuilder the plugin's builder interface. type PluginsBuilder interface { Build(pName string, config map[string]interface{}, middlewareName string) (plugins.Constructor, error) @@ -54,6 +55,6 @@ func (s *traceablePlugin) ServeHTTP(rw http.ResponseWriter, req *http.Request) { s.h.ServeHTTP(rw, req) } -func (s *traceablePlugin) GetTracingInformation() (string, ext.SpanKindEnum) { - return s.name, tracing.SpanKindNoneEnum +func (s *traceablePlugin) GetTracingInformation() (string, string, trace.SpanKind) { + return s.name, typeName, trace.SpanKindInternal } diff --git a/pkg/server/router/router.go b/pkg/server/router/router.go index 5e4aa043b..4b383e076 100644 --- a/pkg/server/router/router.go +++ b/pkg/server/router/router.go @@ -198,21 +198,20 @@ func (m *Manager) buildHTTPHandler(ctx context.Context, router *runtime.RouterIn mHandler := m.middlewaresBuilder.BuildChain(ctx, router.Middlewares) - tHandler := func(next http.Handler) (http.Handler, error) { - return tracing.NewForwarder(ctx, routerName, router.Service, next), nil - } - chain := alice.New() + chain = chain.Append(tracing.WrapRouterHandler(ctx, routerName, router.Rule, provider.GetQualifiedName(ctx, router.Service))) + if m.metricsRegistry != nil && m.metricsRegistry.IsRouterEnabled() { - chain = chain.Append(metricsMiddle.WrapRouterHandler(ctx, m.metricsRegistry, routerName, provider.GetQualifiedName(ctx, router.Service))) + metricsHandler := metricsMiddle.WrapRouterHandler(ctx, m.metricsRegistry, routerName, provider.GetQualifiedName(ctx, router.Service)) + chain = chain.Append(tracing.WrapMiddleware(ctx, metricsHandler)) } if router.DefaultRule { chain = chain.Append(denyrouterrecursion.WrapHandler(routerName)) } - return chain.Extend(*mHandler).Append(tHandler).Then(sHandler) + return chain.Extend(*mHandler).Then(sHandler) } // BuildDefaultHTTPRouter creates a default HTTP router. diff --git a/pkg/server/server.go b/pkg/server/server.go index c17464621..0f4379f04 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -3,6 +3,7 @@ package server import ( "context" "errors" + "io" "os" "os/signal" "time" @@ -27,12 +28,12 @@ type Server struct { stopChan chan bool routinesPool *safe.Pool + + tracerCloser io.Closer } // NewServer returns an initialized Server. -func NewServer(routinesPool *safe.Pool, entryPoints TCPEntryPoints, entryPointsUDP UDPEntryPoints, watcher *ConfigurationWatcher, - chainBuilder *middleware.ChainBuilder, accessLoggerMiddleware *accesslog.Handler, -) *Server { +func NewServer(routinesPool *safe.Pool, entryPoints TCPEntryPoints, entryPointsUDP UDPEntryPoints, watcher *ConfigurationWatcher, chainBuilder *middleware.ChainBuilder, accessLoggerMiddleware *accesslog.Handler, tracerCloser io.Closer) *Server { srv := &Server{ watcher: watcher, tcpEntryPoints: entryPoints, @@ -42,6 +43,7 @@ func NewServer(routinesPool *safe.Pool, entryPoints TCPEntryPoints, entryPointsU stopChan: make(chan bool, 1), routinesPool: routinesPool, udpEntryPoints: entryPointsUDP, + tracerCloser: tracerCloser, } srv.configureSignals() @@ -105,6 +107,12 @@ func (s *Server) Close() { s.chainBuilder.Close() + if s.tracerCloser != nil { + if err := s.tracerCloser.Close(); err != nil { + log.Error().Err(err).Msg("Could not close the tracer") + } + } + cancel() } diff --git a/pkg/server/service/proxy.go b/pkg/server/service/proxy.go index 413a97a6c..083875f9e 100644 --- a/pkg/server/service/proxy.go +++ b/pkg/server/service/proxy.go @@ -22,9 +22,13 @@ const StatusClientClosedRequest = 499 const StatusClientClosedRequestText = "Client Closed Request" func buildSingleHostProxy(target *url.URL, passHostHeader bool, flushInterval time.Duration, roundTripper http.RoundTripper, bufferPool httputil.BufferPool) http.Handler { + // Wrapping the roundTripper with the Tracing roundTripper, + // to handle the reverseProxy client span creation. + tracingRoundTripper := newTracingRoundTripper(roundTripper) + return &httputil.ReverseProxy{ Director: directorBuilder(target, passHostHeader), - Transport: roundTripper, + Transport: tracingRoundTripper, FlushInterval: flushInterval, BufferPool: bufferPool, ErrorHandler: errorHandler, @@ -94,23 +98,7 @@ func isWebSocketUpgrade(req *http.Request) bool { } func errorHandler(w http.ResponseWriter, req *http.Request, err error) { - statusCode := http.StatusInternalServerError - - switch { - case errors.Is(err, io.EOF): - statusCode = http.StatusBadGateway - case errors.Is(err, context.Canceled): - statusCode = StatusClientClosedRequest - default: - var netErr net.Error - if errors.As(err, &netErr) { - if netErr.Timeout() { - statusCode = http.StatusGatewayTimeout - } else { - statusCode = http.StatusBadGateway - } - } - } + statusCode := computeStatusCode(err) logger := log.Ctx(req.Context()) logger.Debug().Err(err).Msgf("%d %s", statusCode, statusText(statusCode)) @@ -121,6 +109,26 @@ func errorHandler(w http.ResponseWriter, req *http.Request, err error) { } } +func computeStatusCode(err error) int { + switch { + case errors.Is(err, io.EOF): + return http.StatusBadGateway + case errors.Is(err, context.Canceled): + return StatusClientClosedRequest + default: + var netErr net.Error + if errors.As(err, &netErr) { + if netErr.Timeout() { + return http.StatusGatewayTimeout + } + + return http.StatusBadGateway + } + } + + return http.StatusInternalServerError +} + func statusText(statusCode int) string { if statusCode == StatusClientClosedRequest { return StatusClientClosedRequestText diff --git a/pkg/server/service/service.go b/pkg/server/service/service.go index 61f6859f4..55fcb9fa2 100644 --- a/pkg/server/service/service.go +++ b/pkg/server/service/service.go @@ -14,6 +14,7 @@ import ( "strings" "time" + "github.com/containous/alice" "github.com/rs/zerolog/log" "github.com/traefik/traefik/v3/pkg/config/dynamic" "github.com/traefik/traefik/v3/pkg/config/runtime" @@ -22,6 +23,7 @@ import ( "github.com/traefik/traefik/v3/pkg/metrics" "github.com/traefik/traefik/v3/pkg/middlewares/accesslog" metricsMiddle "github.com/traefik/traefik/v3/pkg/middlewares/metrics" + tracingMiddle "github.com/traefik/traefik/v3/pkg/middlewares/tracing" "github.com/traefik/traefik/v3/pkg/safe" "github.com/traefik/traefik/v3/pkg/server/cookie" "github.com/traefik/traefik/v3/pkg/server/provider" @@ -305,9 +307,18 @@ func (m *Manager) getLoadBalancerServiceHandler(ctx context.Context, serviceName proxy = accesslog.NewFieldHandler(proxy, accesslog.ServiceName, serviceName, accesslog.AddServiceFields) if m.metricsRegistry != nil && m.metricsRegistry.IsSvcEnabled() { - proxy = metricsMiddle.NewServiceMiddleware(ctx, proxy, m.metricsRegistry, serviceName) + metricsHandler := metricsMiddle.WrapServiceHandler(ctx, m.metricsRegistry, serviceName) + + proxy, err = alice.New(). + Append(tracingMiddle.WrapMiddleware(ctx, metricsHandler)). + Then(proxy) + if err != nil { + return nil, fmt.Errorf("error wrapping metrics handler: %w", err) + } } + proxy = tracingMiddle.NewService(ctx, serviceName, proxy) + lb.Add(proxyName, proxy, nil) // servers are considered UP by default. diff --git a/pkg/server/service/tracing_roundtripper.go b/pkg/server/service/tracing_roundtripper.go new file mode 100644 index 000000000..bdb2ab4f3 --- /dev/null +++ b/pkg/server/service/tracing_roundtripper.go @@ -0,0 +1,42 @@ +package service + +import ( + "context" + "net/http" + + "github.com/traefik/traefik/v3/pkg/tracing" + "go.opentelemetry.io/otel/trace" +) + +type wrapper struct { + rt http.RoundTripper +} + +func (t *wrapper) RoundTrip(req *http.Request) (*http.Response, error) { + var span trace.Span + if tracer := tracing.TracerFromContext(req.Context()); tracer != nil { + var tracingCtx context.Context + tracingCtx, span = tracer.Start(req.Context(), "ReverseProxy", trace.WithSpanKind(trace.SpanKindClient)) + defer span.End() + + req = req.WithContext(tracingCtx) + + tracing.LogClientRequest(span, req) + tracing.InjectContextIntoCarrier(req) + } + + response, err := t.rt.RoundTrip(req) + if err != nil { + statusCode := computeStatusCode(err) + tracing.LogResponseCode(span, statusCode, trace.SpanKindClient) + return response, err + } + + tracing.LogResponseCode(span, response.StatusCode, trace.SpanKindClient) + + return response, nil +} + +func newTracingRoundTripper(rt http.RoundTripper) http.RoundTripper { + return &wrapper{rt: rt} +} diff --git a/pkg/tracing/datadog/datadog.go b/pkg/tracing/datadog/datadog.go deleted file mode 100644 index 0bdacff7b..000000000 --- a/pkg/tracing/datadog/datadog.go +++ /dev/null @@ -1,84 +0,0 @@ -package datadog - -import ( - "io" - "net" - "os" - - "github.com/opentracing/opentracing-go" - "github.com/rs/zerolog/log" - "github.com/traefik/traefik/v3/pkg/logs" - ddtracer "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/opentracer" - datadog "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer" -) - -// Name sets the name of this tracer. -const Name = "datadog" - -// Config provides configuration settings for a datadog tracer. -type Config struct { - LocalAgentHostPort string `description:"Sets the Datadog Agent host:port." json:"localAgentHostPort,omitempty" toml:"localAgentHostPort,omitempty" yaml:"localAgentHostPort,omitempty"` - LocalAgentSocket string `description:"Sets the socket for the Datadog Agent." json:"localAgentSocket,omitempty" toml:"localAgentSocket,omitempty" yaml:"localAgentSocket,omitempty"` - GlobalTags map[string]string `description:"Sets a list of key:value tags on all spans." json:"globalTags,omitempty" toml:"globalTags,omitempty" yaml:"globalTags,omitempty" export:"true"` - Debug bool `description:"Enables Datadog debug." json:"debug,omitempty" toml:"debug,omitempty" yaml:"debug,omitempty" export:"true"` - PrioritySampling bool `description:"Enables priority sampling. When using distributed tracing, this option must be enabled in order to get all the parts of a distributed trace sampled." json:"prioritySampling,omitempty" toml:"prioritySampling,omitempty" yaml:"prioritySampling,omitempty" export:"true"` - TraceIDHeaderName string `description:"Sets the header name used to store the trace ID." json:"traceIDHeaderName,omitempty" toml:"traceIDHeaderName,omitempty" yaml:"traceIDHeaderName,omitempty" export:"true"` - ParentIDHeaderName string `description:"Sets the header name used to store the parent ID." json:"parentIDHeaderName,omitempty" toml:"parentIDHeaderName,omitempty" yaml:"parentIDHeaderName,omitempty" export:"true"` - SamplingPriorityHeaderName string `description:"Sets the header name used to store the sampling priority." json:"samplingPriorityHeaderName,omitempty" toml:"samplingPriorityHeaderName,omitempty" yaml:"samplingPriorityHeaderName,omitempty" export:"true"` - BagagePrefixHeaderName string `description:"Sets the header name prefix used to store baggage items in a map." json:"bagagePrefixHeaderName,omitempty" toml:"bagagePrefixHeaderName,omitempty" yaml:"bagagePrefixHeaderName,omitempty" export:"true"` -} - -// SetDefaults sets the default values. -func (c *Config) SetDefaults() { - host, ok := os.LookupEnv("DD_AGENT_HOST") - if !ok { - host = "localhost" - } - - port, ok := os.LookupEnv("DD_TRACE_AGENT_PORT") - if !ok { - port = "8126" - } - - c.LocalAgentHostPort = net.JoinHostPort(host, port) -} - -// Setup sets up the tracer. -func (c *Config) Setup(serviceName string) (opentracing.Tracer, io.Closer, error) { - logger := log.With().Str(logs.TracingProviderName, Name).Logger() - - opts := []datadog.StartOption{ - datadog.WithService(serviceName), - datadog.WithDebugMode(c.Debug), - datadog.WithPropagator(datadog.NewPropagator(&datadog.PropagatorConfig{ - TraceHeader: c.TraceIDHeaderName, - ParentHeader: c.ParentIDHeaderName, - PriorityHeader: c.SamplingPriorityHeaderName, - BaggagePrefix: c.BagagePrefixHeaderName, - })), - datadog.WithLogger(logs.NewDatadogLogger(logger)), - } - - if c.LocalAgentSocket != "" { - opts = append(opts, datadog.WithUDS(c.LocalAgentSocket)) - } else { - opts = append(opts, datadog.WithAgentAddr(c.LocalAgentHostPort)) - } - - for k, v := range c.GlobalTags { - opts = append(opts, datadog.WithGlobalTag(k, v)) - } - - if c.PrioritySampling { - opts = append(opts, datadog.WithPrioritySampling()) - } - - tracer := ddtracer.New(opts...) - - // Without this, child spans are getting the NOOP tracer - opentracing.SetGlobalTracer(tracer) - - logger.Debug().Msg("Datadog tracer configured") - - return tracer, nil, nil -} diff --git a/pkg/tracing/elastic/elastic.go b/pkg/tracing/elastic/elastic.go deleted file mode 100644 index 383cca2bd..000000000 --- a/pkg/tracing/elastic/elastic.go +++ /dev/null @@ -1,74 +0,0 @@ -package elastic - -import ( - "io" - "net/url" - - "github.com/opentracing/opentracing-go" - "github.com/rs/zerolog/log" - "github.com/traefik/traefik/v3/pkg/logs" - "github.com/traefik/traefik/v3/pkg/version" - "go.elastic.co/apm" - "go.elastic.co/apm/module/apmot" - "go.elastic.co/apm/transport" -) - -// Name sets the name of this tracer. -const Name = "elastic" - -func init() { - // The APM lib uses the init() function to create a default tracer. - // So this default tracer must be disabled. - // https://github.com/elastic/apm-agent-go/blob/8dd383d0d21776faad8841fe110f35633d199a03/tracer.go#L61-L65 - apm.DefaultTracer.Close() -} - -// Config provides configuration settings for a elastic.co tracer. -type Config struct { - ServerURL string `description:"Sets the URL of the Elastic APM server." json:"serverURL,omitempty" toml:"serverURL,omitempty" yaml:"serverURL,omitempty"` - SecretToken string `description:"Sets the token used to connect to Elastic APM Server." json:"secretToken,omitempty" toml:"secretToken,omitempty" yaml:"secretToken,omitempty" loggable:"false"` - ServiceEnvironment string `description:"Sets the name of the environment Traefik is deployed in, e.g. 'production' or 'staging'." json:"serviceEnvironment,omitempty" toml:"serviceEnvironment,omitempty" yaml:"serviceEnvironment,omitempty" export:"true"` -} - -// Setup sets up the tracer. -func (c *Config) Setup(serviceName string) (opentracing.Tracer, io.Closer, error) { - // Create default transport. - tr, err := transport.NewHTTPTransport() - if err != nil { - return nil, nil, err - } - - if c.ServerURL != "" { - serverURL, err := url.Parse(c.ServerURL) - if err != nil { - return nil, nil, err - } - tr.SetServerURL(serverURL) - } - - if c.SecretToken != "" { - tr.SetSecretToken(c.SecretToken) - } - - tracer, err := apm.NewTracerOptions(apm.TracerOptions{ - ServiceName: serviceName, - ServiceVersion: version.Version, - ServiceEnvironment: c.ServiceEnvironment, - Transport: tr, - }) - if err != nil { - return nil, nil, err - } - - logger := log.With().Str(logs.TracingProviderName, Name).Logger() - tracer.SetLogger(logs.NewElasticLogger(logger)) - - otTracer := apmot.New(apmot.WithTracer(tracer)) - - // Without this, child spans are getting the NOOP tracer - opentracing.SetGlobalTracer(otTracer) - - log.Debug().Msg("Elastic tracer configured") - - return otTracer, nil, nil -} diff --git a/pkg/tracing/haystack/haystack.go b/pkg/tracing/haystack/haystack.go deleted file mode 100644 index 6e460dcfb..000000000 --- a/pkg/tracing/haystack/haystack.go +++ /dev/null @@ -1,72 +0,0 @@ -package haystack - -import ( - "io" - "strings" - "time" - - "github.com/ExpediaDotCom/haystack-client-go" - "github.com/opentracing/opentracing-go" - "github.com/rs/zerolog/log" - "github.com/traefik/traefik/v3/pkg/logs" -) - -// Name sets the name of this tracer. -const Name = "haystack" - -// Config provides configuration settings for a haystack tracer. -type Config struct { - LocalAgentHost string `description:"Sets the Haystack Agent host." json:"localAgentHost,omitempty" toml:"localAgentHost,omitempty" yaml:"localAgentHost,omitempty"` - LocalAgentPort int `description:"Sets the Haystack Agent port." json:"localAgentPort,omitempty" toml:"localAgentPort,omitempty" yaml:"localAgentPort,omitempty"` - GlobalTag string `description:"Sets a key:value tag on all spans." json:"globalTag,omitempty" toml:"globalTag,omitempty" yaml:"globalTag,omitempty" export:"true"` - TraceIDHeaderName string `description:"Sets the header name used to store the trace ID." json:"traceIDHeaderName,omitempty" toml:"traceIDHeaderName,omitempty" yaml:"traceIDHeaderName,omitempty" export:"true"` - ParentIDHeaderName string `description:"Sets the header name used to store the parent ID." json:"parentIDHeaderName,omitempty" toml:"parentIDHeaderName,omitempty" yaml:"parentIDHeaderName,omitempty" export:"true"` - SpanIDHeaderName string `description:"Sets the header name used to store the span ID." json:"spanIDHeaderName,omitempty" toml:"spanIDHeaderName,omitempty" yaml:"spanIDHeaderName,omitempty" export:"true"` - BaggagePrefixHeaderName string `description:"Sets the header name prefix used to store baggage items in a map." json:"baggagePrefixHeaderName,omitempty" toml:"baggagePrefixHeaderName,omitempty" yaml:"baggagePrefixHeaderName,omitempty" export:"true"` -} - -// SetDefaults sets the default values. -func (c *Config) SetDefaults() { - c.LocalAgentHost = "127.0.0.1" - c.LocalAgentPort = 35000 -} - -// Setup sets up the tracer. -func (c *Config) Setup(serviceName string) (opentracing.Tracer, io.Closer, error) { - tag := strings.SplitN(c.GlobalTag, ":", 2) - - value := "" - if len(tag) == 2 { - value = tag[1] - } - - host := "localhost" - port := 35000 - if len(c.LocalAgentHost) > 0 { - host = c.LocalAgentHost - } - if c.LocalAgentPort > 0 { - port = c.LocalAgentPort - } - - logger := log.With().Str(logs.TracingProviderName, Name).Logger() - - tracer, closer := haystack.NewTracer(serviceName, haystack.NewAgentDispatcher(host, port, 3*time.Second, 1000), - haystack.TracerOptionsFactory.Tag(tag[0], value), - haystack.TracerOptionsFactory.Propagator(opentracing.HTTPHeaders, - haystack.NewTextMapPropagator(haystack.PropagatorOpts{ - TraceIDKEYName: c.TraceIDHeaderName, - ParentSpanIDKEYName: c.ParentIDHeaderName, - SpanIDKEYName: c.SpanIDHeaderName, - BaggagePrefixKEYName: c.BaggagePrefixHeaderName, - }, haystack.DefaultCodex{})), - haystack.TracerOptionsFactory.Logger(logs.NewHaystackLogger(logger)), - ) - - // Without this, child spans are getting the NOOP tracer - opentracing.SetGlobalTracer(tracer) - - log.Debug().Msg("haystack tracer configured") - - return tracer, closer, nil -} diff --git a/pkg/tracing/instana/instana.go b/pkg/tracing/instana/instana.go deleted file mode 100644 index edb2ee14e..000000000 --- a/pkg/tracing/instana/instana.go +++ /dev/null @@ -1,61 +0,0 @@ -package instana - -import ( - "io" - - instana "github.com/instana/go-sensor" - "github.com/opentracing/opentracing-go" - "github.com/rs/zerolog/log" - "github.com/traefik/traefik/v3/pkg/logs" -) - -// Name sets the name of this tracer. -const Name = "instana" - -// Config provides configuration settings for an instana tracer. -type Config struct { - LocalAgentHost string `description:"Sets the Instana Agent host." json:"localAgentHost,omitempty" toml:"localAgentHost,omitempty" yaml:"localAgentHost,omitempty"` - LocalAgentPort int `description:"Sets the Instana Agent port." json:"localAgentPort,omitempty" toml:"localAgentPort,omitempty" yaml:"localAgentPort,omitempty"` - LogLevel string `description:"Sets the log level for the Instana tracer. ('error','warn','info','debug')" json:"logLevel,omitempty" toml:"logLevel,omitempty" yaml:"logLevel,omitempty" export:"true"` - EnableAutoProfile bool `description:"Enables automatic profiling for the Traefik process." json:"enableAutoProfile,omitempty" toml:"enableAutoProfile,omitempty" yaml:"enableAutoProfile,omitempty" export:"true"` -} - -// SetDefaults sets the default values. -func (c *Config) SetDefaults() { - c.LocalAgentPort = 42699 - c.LogLevel = "info" -} - -// Setup sets up the tracer. -func (c *Config) Setup(serviceName string) (opentracing.Tracer, io.Closer, error) { - // set default logLevel - logLevel := instana.Info - - // check/set logLevel overrides - switch c.LogLevel { - case "error": - logLevel = instana.Error - case "warn": - logLevel = instana.Warn - case "debug": - logLevel = instana.Debug - } - - logger := log.With().Str(logs.TracingProviderName, Name).Logger() - instana.SetLogger(logs.NewInstanaLogger(logger)) - - tracer := instana.NewTracerWithOptions(&instana.Options{ - Service: serviceName, - LogLevel: logLevel, - AgentPort: c.LocalAgentPort, - AgentHost: c.LocalAgentHost, - EnableAutoProfile: c.EnableAutoProfile, - }) - - // Without this, child spans are getting the NOOP tracer - opentracing.SetGlobalTracer(tracer) - - logger.Debug().Msg("Instana tracer configured") - - return tracer, nil, nil -} diff --git a/pkg/tracing/jaeger/jaeger.go b/pkg/tracing/jaeger/jaeger.go deleted file mode 100644 index 64eeb8e18..000000000 --- a/pkg/tracing/jaeger/jaeger.go +++ /dev/null @@ -1,124 +0,0 @@ -package jaeger - -import ( - "fmt" - "io" - - "github.com/opentracing/opentracing-go" - "github.com/rs/zerolog/log" - "github.com/traefik/traefik/v3/pkg/logs" - jaegercli "github.com/uber/jaeger-client-go" - jaegercfg "github.com/uber/jaeger-client-go/config" - "github.com/uber/jaeger-client-go/zipkin" - jaegermet "github.com/uber/jaeger-lib/metrics" -) - -// Name sets the name of this tracer. -const Name = "jaeger" - -// Config provides configuration settings for a jaeger tracer. -type Config struct { - SamplingServerURL string `description:"Sets the sampling server URL." json:"samplingServerURL,omitempty" toml:"samplingServerURL,omitempty" yaml:"samplingServerURL,omitempty"` - SamplingType string `description:"Sets the sampling type." json:"samplingType,omitempty" toml:"samplingType,omitempty" yaml:"samplingType,omitempty" export:"true"` - SamplingParam float64 `description:"Sets the sampling parameter." json:"samplingParam,omitempty" toml:"samplingParam,omitempty" yaml:"samplingParam,omitempty" export:"true"` - LocalAgentHostPort string `description:"Sets the Jaeger Agent host:port." json:"localAgentHostPort,omitempty" toml:"localAgentHostPort,omitempty" yaml:"localAgentHostPort,omitempty"` - Gen128Bit bool `description:"Generates 128 bits span IDs." json:"gen128Bit,omitempty" toml:"gen128Bit,omitempty" yaml:"gen128Bit,omitempty" export:"true"` - Propagation string `description:"Sets the propagation format (jaeger/b3)." json:"propagation,omitempty" toml:"propagation,omitempty" yaml:"propagation,omitempty" export:"true"` - TraceContextHeaderName string `description:"Sets the header name used to store the trace ID." json:"traceContextHeaderName,omitempty" toml:"traceContextHeaderName,omitempty" yaml:"traceContextHeaderName,omitempty" export:"true"` - Collector *Collector `description:"Defines the collector information." json:"collector,omitempty" toml:"collector,omitempty" yaml:"collector,omitempty" export:"true"` - DisableAttemptReconnecting bool `description:"Disables the periodic re-resolution of the agent's hostname and reconnection if there was a change." json:"disableAttemptReconnecting,omitempty" toml:"disableAttemptReconnecting,omitempty" yaml:"disableAttemptReconnecting,omitempty" export:"true"` -} - -// SetDefaults sets the default values. -func (c *Config) SetDefaults() { - c.SamplingServerURL = "http://localhost:5778/sampling" - c.SamplingType = "const" - c.SamplingParam = 1.0 - c.LocalAgentHostPort = "127.0.0.1:6831" - c.Propagation = "jaeger" - c.Gen128Bit = false - c.TraceContextHeaderName = jaegercli.TraceContextHeaderName - c.DisableAttemptReconnecting = true -} - -// Collector provides configuration settings for jaeger collector. -type Collector struct { - Endpoint string `description:"Instructs reporter to send spans to jaeger-collector at this URL." json:"endpoint,omitempty" toml:"endpoint,omitempty" yaml:"endpoint,omitempty"` - User string `description:"User for basic http authentication when sending spans to jaeger-collector." json:"user,omitempty" toml:"user,omitempty" yaml:"user,omitempty" loggable:"false"` - Password string `description:"Password for basic http authentication when sending spans to jaeger-collector." json:"password,omitempty" toml:"password,omitempty" yaml:"password,omitempty" loggable:"false"` -} - -// SetDefaults sets the default values. -func (c *Collector) SetDefaults() { - c.Endpoint = "" - c.User = "" - c.Password = "" -} - -// Setup sets up the tracer. -func (c *Config) Setup(componentName string) (opentracing.Tracer, io.Closer, error) { - reporter := &jaegercfg.ReporterConfig{ - LogSpans: true, - LocalAgentHostPort: c.LocalAgentHostPort, - DisableAttemptReconnecting: c.DisableAttemptReconnecting, - } - - if c.Collector != nil { - reporter.CollectorEndpoint = c.Collector.Endpoint - reporter.User = c.Collector.User - reporter.Password = c.Collector.Password - } - - jcfg := &jaegercfg.Configuration{ - Sampler: &jaegercfg.SamplerConfig{ - SamplingServerURL: c.SamplingServerURL, - Type: c.SamplingType, - Param: c.SamplingParam, - }, - Reporter: reporter, - Headers: &jaegercli.HeadersConfig{ - TraceContextHeaderName: c.TraceContextHeaderName, - }, - } - - // Overrides existing tracer's Configuration with environment variables. - _, err := jcfg.FromEnv() - if err != nil { - return nil, nil, err - } - - jMetricsFactory := jaegermet.NullFactory - - logger := log.With().Str(logs.TracingProviderName, Name).Logger() - - opts := []jaegercfg.Option{ - jaegercfg.Logger(logs.NewJaegerLogger(logger)), - jaegercfg.Metrics(jMetricsFactory), - jaegercfg.Gen128Bit(c.Gen128Bit), - } - - switch c.Propagation { - case "b3": - p := zipkin.NewZipkinB3HTTPHeaderPropagator() - opts = append(opts, - jaegercfg.Injector(opentracing.HTTPHeaders, p), - jaegercfg.Extractor(opentracing.HTTPHeaders, p), - ) - case "jaeger", "": - default: - return nil, nil, fmt.Errorf("unknown propagation format: %s", c.Propagation) - } - - // Initialize tracer with a logger and a metrics factory - closer, err := jcfg.InitGlobalTracer( - componentName, - opts..., - ) - if err != nil { - logger.Warn().Err(err).Msg("Could not initialize jaeger tracer") - return nil, nil, err - } - logger.Debug().Msg("Jaeger tracer configured") - - return opentracing.GlobalTracer(), closer, nil -} diff --git a/pkg/tracing/opentelemetry/opentelemetry.go b/pkg/tracing/opentelemetry/opentelemetry.go index c59fbd410..2e13bc20c 100644 --- a/pkg/tracing/opentelemetry/opentelemetry.go +++ b/pkg/tracing/opentelemetry/opentelemetry.go @@ -5,20 +5,21 @@ import ( "fmt" "io" "net" + "net/url" + "time" - "github.com/opentracing/opentracing-go" "github.com/rs/zerolog/log" "github.com/traefik/traefik/v3/pkg/types" "github.com/traefik/traefik/v3/pkg/version" "go.opentelemetry.io/otel" - oteltracer "go.opentelemetry.io/otel/bridge/opentracing" + "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/exporters/otlp/otlptrace" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/sdk/resource" sdktrace "go.opentelemetry.io/otel/sdk/trace" - semconv "go.opentelemetry.io/otel/semconv/v1.12.0" + semconv "go.opentelemetry.io/otel/semconv/v1.21.0" "go.opentelemetry.io/otel/trace" "google.golang.org/grpc/credentials" "google.golang.org/grpc/encoding/gzip" @@ -26,85 +27,108 @@ import ( // Config provides configuration settings for the open-telemetry tracer. type Config struct { - // NOTE: as no gRPC option is implemented yet, the type is empty and is used as a boolean for upward compatibility purposes. - GRPC *struct{} `description:"gRPC specific configuration for the OpenTelemetry collector." json:"grpc,omitempty" toml:"grpc,omitempty" yaml:"grpc,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` + GRPC *GRPC `description:"gRPC configuration for the OpenTelemetry collector." json:"grpc,omitempty" toml:"grpc,omitempty" yaml:"grpc,omitempty" export:"true"` + HTTP *HTTP `description:"HTTP configuration for the OpenTelemetry collector." json:"http,omitempty" toml:"http,omitempty" yaml:"http,omitempty" export:"true"` +} - Address string `description:"Sets the address (host:port) of the collector endpoint." json:"address,omitempty" toml:"address,omitempty" yaml:"address,omitempty"` - Path string `description:"Sets the URL path of the collector endpoint." json:"path,omitempty" toml:"path,omitempty" yaml:"path,omitempty" export:"true"` - Insecure bool `description:"Disables client transport security for the exporter." json:"insecure,omitempty" toml:"insecure,omitempty" yaml:"insecure,omitempty" export:"true"` - Headers map[string]string `description:"Defines additional headers to be sent with the payloads." json:"headers,omitempty" toml:"headers,omitempty" yaml:"headers,omitempty" export:"true"` - TLS *types.ClientTLS `description:"Defines client transport security parameters." json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" export:"true"` +// GRPC provides configuration settings for the gRPC open-telemetry tracer. +type GRPC 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 *types.ClientTLS `description:"Defines client transport security parameters." json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" export:"true"` } // SetDefaults sets the default values. -func (c *Config) SetDefaults() { - c.Address = "localhost:4318" +func (c *GRPC) SetDefaults() { + c.Endpoint = "localhost:4317" +} + +// HTTP provides configuration settings for the HTTP open-telemetry tracer. +type HTTP struct { + Endpoint string `description:"Sets the HTTP endpoint (scheme://host:port/v1/traces) of the collector." json:"endpoint,omitempty" toml:"endpoint,omitempty" yaml:"endpoint,omitempty"` + TLS *types.ClientTLS `description:"Defines client transport security parameters." json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" export:"true"` +} + +// SetDefaults sets the default values. +func (c *HTTP) SetDefaults() { + c.Endpoint = "localhost:4318" } // Setup sets up the tracer. -func (c *Config) Setup(componentName string) (opentracing.Tracer, io.Closer, error) { +func (c *Config) Setup(serviceName string, sampleRate float64, globalAttributes map[string]string, headers map[string]string) (trace.Tracer, io.Closer, error) { var ( err error exporter *otlptrace.Exporter ) if c.GRPC != nil { - exporter, err = c.setupGRPCExporter() + exporter, err = c.setupGRPCExporter(headers) } else { - exporter, err = c.setupHTTPExporter() + exporter, err = c.setupHTTPExporter(headers) } if err != nil { return nil, nil, fmt.Errorf("setting up exporter: %w", err) } - bt := oteltracer.NewBridgeTracer() - bt.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{})) + attr := []attribute.KeyValue{ + semconv.ServiceNameKey.String(serviceName), + semconv.ServiceVersionKey.String(version.Version), + } - bt.SetOpenTelemetryTracer(otel.Tracer(componentName, trace.WithInstrumentationVersion(version.Version))) - opentracing.SetGlobalTracer(bt) + for k, v := range globalAttributes { + attr = append(attr, attribute.String(k, v)) + } res, err := resource.New(context.Background(), - resource.WithAttributes(semconv.ServiceNameKey.String("traefik")), - resource.WithAttributes(semconv.ServiceVersionKey.String(version.Version)), + resource.WithAttributes(attr...), resource.WithFromEnv(), resource.WithTelemetrySDK(), + resource.WithOSType(), + resource.WithProcessCommandArgs(), ) if err != nil { return nil, nil, fmt.Errorf("building resource: %w", err) } + // Register the trace exporter with a TracerProvider, using a batch + // span processor to aggregate spans before export. + bsp := sdktrace.NewBatchSpanProcessor(exporter) tracerProvider := sdktrace.NewTracerProvider( + sdktrace.WithSampler(sdktrace.TraceIDRatioBased(sampleRate)), sdktrace.WithResource(res), - sdktrace.WithBatcher(exporter), + sdktrace.WithSpanProcessor(bsp), ) + otel.SetTracerProvider(tracerProvider) + otel.SetTextMapPropagator(propagation.TraceContext{}) log.Debug().Msg("OpenTelemetry tracer configured") - return bt, tpCloser{provider: tracerProvider}, err + return tracerProvider.Tracer("github.com/traefik/traefik"), &tpCloser{provider: tracerProvider}, err } -func (c *Config) setupHTTPExporter() (*otlptrace.Exporter, error) { - host, port, err := net.SplitHostPort(c.Address) +func (c *Config) setupHTTPExporter(headers map[string]string) (*otlptrace.Exporter, error) { + endpoint, err := url.Parse(c.HTTP.Endpoint) if err != nil { - return nil, fmt.Errorf("invalid collector address %q: %w", c.Address, err) + return nil, fmt.Errorf("invalid collector endpoint %q: %w", c.HTTP.Endpoint, err) } opts := []otlptracehttp.Option{ - otlptracehttp.WithEndpoint(fmt.Sprintf("%s:%s", host, port)), - otlptracehttp.WithHeaders(c.Headers), + otlptracehttp.WithEndpoint(endpoint.Host), + otlptracehttp.WithHeaders(headers), otlptracehttp.WithCompression(otlptracehttp.GzipCompression), } - if c.Insecure { + if endpoint.Scheme == "http" { opts = append(opts, otlptracehttp.WithInsecure()) } - if c.Path != "" { - opts = append(opts, otlptracehttp.WithURLPath(c.Path)) + if endpoint.Path != "" { + opts = append(opts, otlptracehttp.WithURLPath(endpoint.Path)) } - if c.TLS != nil { - tlsConfig, err := c.TLS.CreateTLSConfig(context.Background()) + if c.HTTP.TLS != nil { + tlsConfig, err := c.HTTP.TLS.CreateTLSConfig(context.Background()) if err != nil { return nil, fmt.Errorf("creating TLS client config: %w", err) } @@ -115,24 +139,24 @@ func (c *Config) setupHTTPExporter() (*otlptrace.Exporter, error) { return otlptrace.New(context.Background(), otlptracehttp.NewClient(opts...)) } -func (c *Config) setupGRPCExporter() (*otlptrace.Exporter, error) { - host, port, err := net.SplitHostPort(c.Address) +func (c *Config) setupGRPCExporter(headers map[string]string) (*otlptrace.Exporter, error) { + host, port, err := net.SplitHostPort(c.GRPC.Endpoint) if err != nil { - return nil, fmt.Errorf("invalid collector address %q: %w", c.Address, err) + return nil, fmt.Errorf("invalid collector address %q: %w", c.GRPC.Endpoint, err) } opts := []otlptracegrpc.Option{ otlptracegrpc.WithEndpoint(fmt.Sprintf("%s:%s", host, port)), - otlptracegrpc.WithHeaders(c.Headers), + otlptracegrpc.WithHeaders(headers), otlptracegrpc.WithCompressor(gzip.Name), } - if c.Insecure { + if c.GRPC.Insecure { opts = append(opts, otlptracegrpc.WithInsecure()) } - if c.TLS != nil { - tlsConfig, err := c.TLS.CreateTLSConfig(context.Background()) + if c.GRPC.TLS != nil { + tlsConfig, err := c.GRPC.TLS.CreateTLSConfig(context.Background()) if err != nil { return nil, fmt.Errorf("creating TLS client config: %w", err) } @@ -148,6 +172,13 @@ type tpCloser struct { provider *sdktrace.TracerProvider } -func (t tpCloser) Close() error { - return t.provider.Shutdown(context.Background()) +func (t *tpCloser) Close() error { + if t == nil { + return nil + } + + ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(5*time.Second)) + defer cancel() + + return t.provider.Shutdown(ctx) } diff --git a/pkg/tracing/opentelemetry/opentelemetry_test.go b/pkg/tracing/opentelemetry/opentelemetry_test.go index 40fcca159..ad7f13a4d 100644 --- a/pkg/tracing/opentelemetry/opentelemetry_test.go +++ b/pkg/tracing/opentelemetry/opentelemetry_test.go @@ -1,4 +1,4 @@ -package opentelemetry +package opentelemetry_test import ( "compress/gzip" @@ -7,14 +7,16 @@ import ( "io" "net/http" "net/http/httptest" - "strings" "testing" "time" + "github.com/containous/alice" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - mtracing "github.com/traefik/traefik/v3/pkg/middlewares/tracing" + "github.com/traefik/traefik/v3/pkg/config/static" + tracingMiddle "github.com/traefik/traefik/v3/pkg/middlewares/tracing" "github.com/traefik/traefik/v3/pkg/tracing" + "github.com/traefik/traefik/v3/pkg/tracing/opentelemetry" "go.opentelemetry.io/collector/pdata/ptrace/ptraceotlp" ) @@ -68,14 +70,25 @@ func TestTracing(t *testing.T) { })) t.Cleanup(collector.Close) - newTracing, err := tracing.NewTracing("", 0, &Config{ - Insecure: true, - Address: strings.TrimPrefix(collector.URL, "http://"), - }) - require.NoError(t, err) - t.Cleanup(newTracing.Close) + tracingConfig := &static.Tracing{ + ServiceName: "traefik", + SampleRate: 1.0, + OTLP: &opentelemetry.Config{ + HTTP: &opentelemetry.HTTP{ + Endpoint: collector.URL, + }, + }, + } - epHandler := mtracing.NewEntryPoint(context.Background(), newTracing, "test", http.NotFoundHandler()) + newTracing, closer, err := tracing.NewTracing(tracingConfig) + require.NoError(t, err) + t.Cleanup(func() { + _ = closer.Close() + }) + + chain := alice.New(tracingMiddle.WrapEntryPointHandler(context.Background(), newTracing, "test")) + epHandler, err := chain.Then(http.NotFoundHandler()) + require.NoError(t, err) for _, test := range tests { t.Run(test.desc, func(t *testing.T) { diff --git a/pkg/tracing/operation_name.go b/pkg/tracing/operation_name.go deleted file mode 100644 index 54e875569..000000000 --- a/pkg/tracing/operation_name.go +++ /dev/null @@ -1,65 +0,0 @@ -package tracing - -import ( - "crypto/sha256" - "encoding/hex" - "strings" - - "github.com/rs/zerolog/log" -) - -// TraceNameHashLength defines the number of characters to use from the head of the generated hash. -const TraceNameHashLength = 8 - -// OperationNameMaxLengthNumber defines the number of static characters in a Span Trace name: -// 8 chars for hash + 2 chars for '_'. -const OperationNameMaxLengthNumber = 10 - -func generateOperationName(prefix string, parts []string, sep string, spanLimit int) string { - name := prefix + " " + strings.Join(parts, sep) - - maxLength := OperationNameMaxLengthNumber + len(prefix) + 1 - - if spanLimit > 0 && len(name) > spanLimit { - if spanLimit < maxLength { - log.Warn().Msgf("SpanNameLimit cannot be lesser than %d: falling back on %d", maxLength, maxLength+3) - spanLimit = maxLength + 3 - } - - limit := (spanLimit - maxLength) / 2 - - var fragments []string - for _, value := range parts { - fragments = append(fragments, truncateString(value, limit)) - } - fragments = append(fragments, computeHash(name)) - - name = prefix + " " + strings.Join(fragments, sep) - } - - return name -} - -// truncateString reduces the length of the 'str' argument to 'num' - 3 and adds a '...' suffix to the tail. -func truncateString(str string, num int) string { - text := str - if len(str) > num { - if num > 3 { - num -= 3 - } - text = str[0:num] + "..." - } - return text -} - -// computeHash returns the first TraceNameHashLength character of the sha256 hash for 'name' argument. -func computeHash(name string) string { - data := []byte(name) - hash := sha256.New() - if _, err := hash.Write(data); err != nil { - // Impossible case - log.Error().Str("OperationName", name).Err(err).Msgf("Failed to create Span name hash for %s", name) - } - - return hex.EncodeToString(hash.Sum(nil))[:TraceNameHashLength] -} diff --git a/pkg/tracing/operation_name_test.go b/pkg/tracing/operation_name_test.go deleted file mode 100644 index 4c9c746bd..000000000 --- a/pkg/tracing/operation_name_test.go +++ /dev/null @@ -1,135 +0,0 @@ -package tracing - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func Test_generateOperationName(t *testing.T) { - testCases := []struct { - desc string - prefix string - parts []string - sep string - spanLimit int - expected string - }{ - { - desc: "empty", - expected: " ", - }, - { - desc: "with prefix, without parts", - prefix: "foo", - parts: []string{}, - sep: "-", - spanLimit: 0, - expected: "foo ", - }, - { - desc: "with prefix, without parts, too small span limit", - prefix: "foo", - parts: []string{}, - sep: "-", - spanLimit: 1, - expected: "foo 6c2d2c76", - }, - { - desc: "with prefix, with parts", - prefix: "foo", - parts: []string{"fii", "fuu", "fee", "faa"}, - sep: "-", - spanLimit: 0, - expected: "foo fii-fuu-fee-faa", - }, - { - desc: "with prefix, with parts, with span limit", - prefix: "foo", - parts: []string{"fff", "ooo", "ooo", "bbb", "aaa", "rrr"}, - sep: "-", - spanLimit: 20, - expected: "foo fff-ooo-ooo-bbb-aaa-rrr-1a8e8ac1", - }, - } - - for _, test := range testCases { - test := test - t.Run(test.desc, func(t *testing.T) { - t.Parallel() - - opName := generateOperationName(test.prefix, test.parts, test.sep, test.spanLimit) - assert.Equal(t, test.expected, opName) - }) - } -} - -func TestComputeHash(t *testing.T) { - testCases := []struct { - desc string - text string - expected string - }{ - { - desc: "hashing", - text: "some very long piece of text", - expected: "0c6e798b", - }, - { - desc: "short text less than limit 10", - text: "short", - expected: "f9b0078b", - }, - } - - for _, test := range testCases { - test := test - t.Run(test.desc, func(t *testing.T) { - t.Parallel() - - actual := computeHash(test.text) - - assert.Equal(t, test.expected, actual) - }) - } -} - -func TestTruncateString(t *testing.T) { - testCases := []struct { - desc string - text string - limit int - expected string - }{ - { - desc: "short text less than limit 10", - text: "short", - limit: 10, - expected: "short", - }, - { - desc: "basic truncate with limit 10", - text: "some very long piece of text", - limit: 10, - expected: "some ve...", - }, - { - desc: "truncate long FQDN to 39 chars", - text: "some-service-100.slug.namespace.environment.domain.tld", - limit: 39, - expected: "some-service-100.slug.namespace.envi...", - }, - } - - for _, test := range testCases { - test := test - t.Run(test.desc, func(t *testing.T) { - t.Parallel() - - actual := truncateString(test.text, test.limit) - - assert.Equal(t, test.expected, actual) - assert.LessOrEqual(t, len(actual), test.limit) - }) - } -} diff --git a/pkg/tracing/tracing.go b/pkg/tracing/tracing.go index d8923f510..6bb382920 100644 --- a/pkg/tracing/tracing.go +++ b/pkg/tracing/tracing.go @@ -2,182 +2,213 @@ package tracing import ( "context" - "errors" "fmt" "io" + "net" "net/http" + "strconv" - "github.com/opentracing/opentracing-go" - "github.com/opentracing/opentracing-go/ext" "github.com/rs/zerolog/log" + "github.com/traefik/traefik/v3/pkg/config/static" + "github.com/traefik/traefik/v3/pkg/tracing/opentelemetry" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/codes" + "go.opentelemetry.io/otel/propagation" + semconv "go.opentelemetry.io/otel/semconv/v1.21.0" + "go.opentelemetry.io/otel/trace" ) -type contextKey int - -const ( - // SpanKindNoneEnum Span kind enum none. - SpanKindNoneEnum ext.SpanKindEnum = "none" - tracingKey contextKey = iota -) - -// WithTracing Adds Tracing into the context. -func WithTracing(ctx context.Context, tracing *Tracing) context.Context { - return context.WithValue(ctx, tracingKey, tracing) -} - -// FromContext Gets Tracing from context. -func FromContext(ctx context.Context) (*Tracing, error) { - if ctx == nil { - panic("nil context") - } - - tracer, ok := ctx.Value(tracingKey).(*Tracing) - if !ok { - return nil, errors.New("unable to find tracing in the context") - } - return tracer, nil -} - -// Backend is an abstraction for tracking backend (Jaeger, Zipkin, ...). +// Backend is an abstraction for tracking backend (OpenTelemetry, ...). type Backend interface { - Setup(componentName string) (opentracing.Tracer, io.Closer, error) -} - -// Tracing middleware. -type Tracing struct { - ServiceName string `description:"Sets the name for this service" export:"true"` - SpanNameLimit int `description:"Sets the maximum character limit for span names (default 0 = no limit)" export:"true"` - - tracer opentracing.Tracer - closer io.Closer + Setup(serviceName string, sampleRate float64, globalAttributes map[string]string, headers map[string]string) (trace.Tracer, io.Closer, error) } // NewTracing Creates a Tracing. -func NewTracing(serviceName string, spanNameLimit int, tracingBackend Backend) (*Tracing, error) { - tracing := &Tracing{ - ServiceName: serviceName, - SpanNameLimit: spanNameLimit, +func NewTracing(conf *static.Tracing) (trace.Tracer, io.Closer, error) { + var backend Backend + + if conf.OTLP != nil { + backend = conf.OTLP } - var err error - tracing.tracer, tracing.closer, err = tracingBackend.Setup(serviceName) + if backend == nil { + log.Debug().Msg("Could not initialize tracing, using OpenTelemetry by default") + defaultBackend := &opentelemetry.Config{} + backend = defaultBackend + } + + return backend.Setup(conf.ServiceName, conf.SampleRate, conf.GlobalAttributes, conf.Headers) +} + +// TracerFromContext extracts the trace.Tracer from the given context. +func TracerFromContext(ctx context.Context) trace.Tracer { + span := trace.SpanFromContext(ctx) + if span != nil && span.TracerProvider() != nil { + return span.TracerProvider().Tracer("github.com/traefik/traefik") + } + + return nil +} + +// ExtractCarrierIntoContext reads cross-cutting concerns from the carrier into a Context. +func ExtractCarrierIntoContext(ctx context.Context, headers http.Header) context.Context { + propagator := propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}) + return propagator.Extract(ctx, propagation.HeaderCarrier(headers)) +} + +// InjectContextIntoCarrier sets cross-cutting concerns from the request context into the request headers. +func InjectContextIntoCarrier(req *http.Request) { + propagator := propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}) + propagator.Inject(req.Context(), propagation.HeaderCarrier(req.Header)) +} + +// SetStatusErrorf flags the span as in error and log an event. +func SetStatusErrorf(ctx context.Context, format string, args ...interface{}) { + if span := trace.SpanFromContext(ctx); span != nil { + span.SetStatus(codes.Error, fmt.Sprintf(format, args...)) + } +} + +// LogClientRequest used to add span attributes from the request as a Client. +// TODO: the semconv does not implement Semantic Convention v1.23.0. +func LogClientRequest(span trace.Span, r *http.Request) { + if r == nil || span == nil { + return + } + + // Common attributes https://github.com/open-telemetry/semantic-conventions/blob/v1.23.0/docs/http/http-spans.md#common-attributes + span.SetAttributes(semconv.HTTPRequestMethodKey.String(r.Method)) + span.SetAttributes(semconv.NetworkProtocolVersion(proto(r.Proto))) + + // Client attributes https://github.com/open-telemetry/semantic-conventions/blob/v1.23.0/docs/http/http-spans.md#http-client + span.SetAttributes(semconv.URLFull(r.URL.String())) + span.SetAttributes(semconv.URLScheme(r.URL.Scheme)) + span.SetAttributes(semconv.UserAgentOriginal(r.UserAgent())) + + host, port, err := net.SplitHostPort(r.URL.Host) if err != nil { - return nil, err - } - return tracing, nil -} - -// StartSpan delegates to opentracing.Tracer. -func (t *Tracing) StartSpan(operationName string, opts ...opentracing.StartSpanOption) opentracing.Span { - return t.tracer.StartSpan(operationName, opts...) -} - -// StartSpanf delegates to StartSpan. -func (t *Tracing) StartSpanf(r *http.Request, spanKind ext.SpanKindEnum, opPrefix string, opParts []string, separator string, opts ...opentracing.StartSpanOption) (opentracing.Span, *http.Request, func()) { - operationName := generateOperationName(opPrefix, opParts, separator, t.SpanNameLimit) - - return StartSpan(r, operationName, spanKind, opts...) -} - -// Inject delegates to opentracing.Tracer. -func (t *Tracing) Inject(sm opentracing.SpanContext, format, carrier interface{}) error { - return t.tracer.Inject(sm, format, carrier) -} - -// Extract delegates to opentracing.Tracer. -func (t *Tracing) Extract(format, carrier interface{}) (opentracing.SpanContext, error) { - return t.tracer.Extract(format, carrier) -} - -// IsEnabled determines if tracing was successfully activated. -func (t *Tracing) IsEnabled() bool { - return t != nil && t.tracer != nil -} - -// Close tracer. -func (t *Tracing) Close() { - if t.closer != nil { - err := t.closer.Close() - if err != nil { - log.Warn().Err(err).Send() + span.SetAttributes(attribute.String("network.peer.address", host)) + span.SetAttributes(semconv.ServerAddress(r.URL.Host)) + switch r.URL.Scheme { + case "http": + span.SetAttributes(attribute.String("network.peer.port", "80")) + span.SetAttributes(semconv.ServerPort(80)) + case "https": + span.SetAttributes(attribute.String("network.peer.port", "443")) + span.SetAttributes(semconv.ServerPort(443)) } + } else { + span.SetAttributes(attribute.String("network.peer.address", host)) + span.SetAttributes(attribute.String("network.peer.port", port)) + intPort, _ := strconv.Atoi(port) + span.SetAttributes(semconv.ServerAddress(host)) + span.SetAttributes(semconv.ServerPort(intPort)) } } -// LogRequest used to create span tags from the request. -func LogRequest(span opentracing.Span, r *http.Request) { - if span != nil && r != nil { - ext.HTTPMethod.Set(span, r.Method) - ext.HTTPUrl.Set(span, r.URL.String()) - span.SetTag("http.host", r.Host) +// LogServerRequest used to add span attributes from the request as a Server. +// TODO: the semconv does not implement Semantic Convention v1.23.0. +func LogServerRequest(span trace.Span, r *http.Request) { + if r == nil { + return + } + + // Common attributes https://github.com/open-telemetry/semantic-conventions/blob/v1.23.0/docs/http/http-spans.md#common-attributes + span.SetAttributes(semconv.HTTPRequestMethodKey.String(r.Method)) + span.SetAttributes(semconv.NetworkProtocolVersion(proto(r.Proto))) + + // Server attributes https://github.com/open-telemetry/semantic-conventions/blob/v1.23.0/docs/http/http-spans.md#http-server-semantic-conventions + span.SetAttributes(semconv.HTTPRequestBodySize(int(r.ContentLength))) + span.SetAttributes(semconv.URLPath(r.URL.Path)) + span.SetAttributes(semconv.URLQuery(r.URL.RawQuery)) + span.SetAttributes(semconv.URLScheme(r.Header.Get("X-Forwarded-Proto"))) + span.SetAttributes(semconv.UserAgentOriginal(r.UserAgent())) + span.SetAttributes(semconv.ServerAddress(r.Host)) + + host, port, err := net.SplitHostPort(r.RemoteAddr) + if err != nil { + span.SetAttributes(semconv.ClientAddress(r.RemoteAddr)) + span.SetAttributes(attribute.String("network.peer.address", r.RemoteAddr)) + } else { + span.SetAttributes(attribute.String("network.peer.address", host)) + span.SetAttributes(attribute.String("network.peer.port", port)) + span.SetAttributes(semconv.ClientAddress(host)) + intPort, _ := strconv.Atoi(port) + span.SetAttributes(semconv.ClientPort(intPort)) + } + + span.SetAttributes(semconv.ClientSocketAddress(r.Header.Get("X-Forwarded-For"))) +} + +func proto(proto string) string { + switch proto { + case "HTTP/1.0": + return "1.0" + case "HTTP/1.1": + return "1.1" + case "HTTP/2": + return "2" + case "HTTP/3": + return "3" + default: + return proto } } // LogResponseCode used to log response code in span. -func LogResponseCode(span opentracing.Span, code int) { +func LogResponseCode(span trace.Span, code int, spanKind trace.SpanKind) { if span != nil { - ext.HTTPStatusCode.Set(span, uint16(code)) - if code >= http.StatusInternalServerError { - ext.Error.Set(span, true) + var status codes.Code + var desc string + switch spanKind { + case trace.SpanKindServer: + status, desc = ServerStatus(code) + case trace.SpanKindClient: + status, desc = ClientStatus(code) + default: + status, desc = DefaultStatus(code) + } + span.SetStatus(status, desc) + if code > 0 { + span.SetAttributes(semconv.HTTPResponseStatusCode(code)) } } } -// GetSpan used to retrieve span from request context. -func GetSpan(r *http.Request) opentracing.Span { - return opentracing.SpanFromContext(r.Context()) -} - -// InjectRequestHeaders used to inject OpenTracing headers into the request. -func InjectRequestHeaders(r *http.Request) { - if span := GetSpan(r); span != nil { - err := opentracing.GlobalTracer().Inject( - span.Context(), - opentracing.HTTPHeaders, - opentracing.HTTPHeadersCarrier(r.Header)) - if err != nil { - log.Ctx(r.Context()).Error().Err(err).Send() - } +// ServerStatus returns a span status code and message for an HTTP status code +// value returned by a server. Status codes in the 400-499 range are not +// returned as errors. +func ServerStatus(code int) (codes.Code, string) { + if code < 100 || code >= 600 { + return codes.Error, fmt.Sprintf("Invalid HTTP status code %d", code) } -} - -// LogEventf logs an event to the span in the request context. -func LogEventf(r *http.Request, format string, args ...interface{}) { - if span := GetSpan(r); span != nil { - span.LogKV("event", fmt.Sprintf(format, args...)) + if code >= 500 { + return codes.Error, "" } + return codes.Unset, "" } -// StartSpan starts a new span from the one in the request context. -func StartSpan(r *http.Request, operationName string, spanKind ext.SpanKindEnum, opts ...opentracing.StartSpanOption) (opentracing.Span, *http.Request, func()) { - span, ctx := opentracing.StartSpanFromContext(r.Context(), operationName, opts...) - - switch spanKind { - case ext.SpanKindRPCClientEnum: - ext.SpanKindRPCClient.Set(span) - case ext.SpanKindRPCServerEnum: - ext.SpanKindRPCServer.Set(span) - case ext.SpanKindProducerEnum: - ext.SpanKindProducer.Set(span) - case ext.SpanKindConsumerEnum: - ext.SpanKindConsumer.Set(span) - default: - // noop +// ClientStatus returns a span status code and message for an HTTP status code +// value returned by a server. Status codes in the 400-499 range are not +// returned as errors. +func ClientStatus(code int) (codes.Code, string) { + if code < 100 || code >= 600 { + return codes.Error, fmt.Sprintf("Invalid HTTP status code %d", code) } - - r = r.WithContext(ctx) - return span, r, func() { span.Finish() } -} - -// SetError flags the span associated with this request as in error. -func SetError(r *http.Request) { - if span := GetSpan(r); span != nil { - ext.Error.Set(span, true) + if code >= 400 { + return codes.Error, "" } + return codes.Unset, "" } -// SetErrorWithEvent flags the span associated with this request as in error and log an event. -func SetErrorWithEvent(r *http.Request, format string, args ...interface{}) { - SetError(r) - LogEventf(r, format, args...) +// DefaultStatus returns a span status code and message for an HTTP status code +// value generated internally. +func DefaultStatus(code int) (codes.Code, string) { + if code < 100 || code >= 600 { + return codes.Error, fmt.Sprintf("Invalid HTTP status code %d", code) + } + if code >= 500 { + return codes.Error, "" + } + return codes.Unset, "" } diff --git a/pkg/tracing/zipkin/zipkin.go b/pkg/tracing/zipkin/zipkin.go deleted file mode 100644 index 598f38037..000000000 --- a/pkg/tracing/zipkin/zipkin.go +++ /dev/null @@ -1,71 +0,0 @@ -package zipkin - -import ( - "io" - "time" - - "github.com/opentracing/opentracing-go" - zipkinot "github.com/openzipkin-contrib/zipkin-go-opentracing" - "github.com/openzipkin/zipkin-go" - "github.com/openzipkin/zipkin-go/reporter/http" - "github.com/rs/zerolog/log" -) - -// Name sets the name of this tracer. -const Name = "zipkin" - -// Config provides configuration settings for a zipkin tracer. -type Config struct { - HTTPEndpoint string `description:"Sets the HTTP Endpoint to report traces to." json:"httpEndpoint,omitempty" toml:"httpEndpoint,omitempty" yaml:"httpEndpoint,omitempty"` - SameSpan bool `description:"Uses SameSpan RPC style traces." json:"sameSpan,omitempty" toml:"sameSpan,omitempty" yaml:"sameSpan,omitempty" export:"true"` - ID128Bit bool `description:"Uses 128 bits root span IDs." json:"id128Bit,omitempty" toml:"id128Bit,omitempty" yaml:"id128Bit,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"` -} - -// SetDefaults sets the default values. -func (c *Config) SetDefaults() { - c.HTTPEndpoint = "http://localhost:9411/api/v2/spans" - c.SameSpan = false - c.ID128Bit = true - c.SampleRate = 1.0 -} - -// Setup sets up the tracer. -func (c *Config) Setup(serviceName string) (opentracing.Tracer, io.Closer, error) { - // create our local endpoint - endpoint, err := zipkin.NewEndpoint(serviceName, "0.0.0.0:0") - if err != nil { - return nil, nil, err - } - - // create our sampler - sampler, err := zipkin.NewBoundarySampler(c.SampleRate, time.Now().Unix()) - if err != nil { - return nil, nil, err - } - - // create the span reporter - reporter := http.NewReporter(c.HTTPEndpoint) - - // create the native Zipkin tracer - nativeTracer, err := zipkin.NewTracer( - reporter, - zipkin.WithLocalEndpoint(endpoint), - zipkin.WithSharedSpans(c.SameSpan), - zipkin.WithTraceID128Bit(c.ID128Bit), - zipkin.WithSampler(sampler), - ) - if err != nil { - return nil, nil, err - } - - // wrap the Zipkin native tracer with the OpenTracing Bridge - tracer := zipkinot.Wrap(nativeTracer) - - // Without this, child spans are getting the NOOP tracer - opentracing.SetGlobalTracer(tracer) - - log.Debug().Msg("Zipkin tracer configured") - - return tracer, reporter, nil -}