mirror of
https://github.com/containous/traefik.git
synced 2024-12-22 13:34:03 +03:00
Migrate to opentelemetry
This commit is contained in:
parent
45bb00be04
commit
4ddef9830b
@ -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() {
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
```
|
@ -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).
|
@ -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
|
||||
```
|
@ -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
|
||||
```
|
@ -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
|
||||
```
|
@ -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="`<host>:<port>`"_
|
||||
_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="`<scheme>://<host>:<port><path>`"_
|
||||
|
||||
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="`<host>:<port>`"_
|
||||
|
||||
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
|
||||
```
|
||||
|
@ -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
|
||||
```
|
||||
|
@ -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
|
||||
```
|
@ -987,170 +987,50 @@ Defines the allowed SPIFFE trust domain.
|
||||
`--tracing`:
|
||||
OpenTracing configuration. (Default: ```false```)
|
||||
|
||||
`--tracing.datadog`:
|
||||
Settings for Datadog. (Default: ```false```)
|
||||
`--tracing.globalattributes.<name>`:
|
||||
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.<name>`:
|
||||
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.<name>`:
|
||||
`--tracing.headers.<name>`:
|
||||
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```)
|
||||
|
@ -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_<NAME>`:
|
||||
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_<NAME>`:
|
||||
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_<NAME>`:
|
||||
`TRAEFIK_TRACING_HEADERS_<NAME>`:
|
||||
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```)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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'
|
||||
|
96
go.mod
96
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
|
||||
|
283
go.sum
283
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=
|
||||
|
21
integration/fixtures/tracing/otel-collector-config.yaml
Normal file
21
integration/fixtures/tracing/otel-collector-config.yaml
Normal file
@ -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:
|
@ -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}}"
|
@ -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
|
@ -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}}"
|
56
integration/fixtures/tracing/tempo.yaml
Normal file
56
integration/fixtures/tracing/tempo.yaml
Normal file
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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"`
|
||||
}
|
||||
|
@ -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{
|
||||
|
2
pkg/api/testdata/overview-features.json
vendored
2
pkg/api/testdata/overview-features.json
vendored
@ -2,7 +2,7 @@
|
||||
"features": {
|
||||
"accessLog": false,
|
||||
"metrics": "Prometheus",
|
||||
"tracing": "Jaeger"
|
||||
"tracing": ""
|
||||
},
|
||||
"http": {
|
||||
"middlewares": {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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...)
|
||||
}
|
@ -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, "<nil> INF haystack_test.go:21 > foo\n", buf.String())
|
||||
}
|
@ -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...)
|
||||
}
|
@ -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, "<nil> DBG jaeger_test.go:21 > foo\n", buf.String())
|
||||
}
|
@ -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"
|
||||
)
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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, ",") {
|
||||
|
@ -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()))
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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) {
|
||||
|
@ -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.
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -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())
|
||||
}
|
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
71
pkg/middlewares/tracing/middleware.go
Normal file
71
pkg/middlewares/tracing/middleware.go
Normal file
@ -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)
|
||||
}
|
||||
}
|
@ -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{} }
|
||||
|
60
pkg/middlewares/tracing/router.go
Normal file
60
pkg/middlewares/tracing/router.go
Normal file
@ -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)
|
||||
}
|
86
pkg/middlewares/tracing/router_test.go
Normal file
86
pkg/middlewares/tracing/router_test.go
Normal file
@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
45
pkg/middlewares/tracing/service.go
Normal file
45
pkg/middlewares/tracing/service.go
Normal file
@ -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)
|
||||
}
|
80
pkg/middlewares/tracing/service_test.go
Normal file
80
pkg/middlewares/tracing/service_test.go
Normal file
@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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",
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -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 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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()
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
42
pkg/server/service/tracing_roundtripper.go
Normal file
42
pkg/server/service/tracing_roundtripper.go
Normal file
@ -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}
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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]
|
||||
}
|
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
@ -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, ""
|
||||
}
|
||||
|
@ -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
|
||||
}
|
Loading…
Reference in New Issue
Block a user