diff --git a/README.md b/README.md index 318a05569..544eddb92 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ _(But if you'd rather configure some of your routes manually, Traefik supports t - Provides HTTPS to your microservices by leveraging [Let's Encrypt](https://letsencrypt.org) (wildcard certificates support) - Circuit breakers, retry - See the magic through its clean web UI -- Websocket, HTTP/2, GRPC ready +- Websocket, HTTP/2, gRPC ready - Provides metrics (Rest, Prometheus, Datadog, Statsd, InfluxDB) - Keeps access logs (JSON, CLF) - Fast diff --git a/cmd/traefik/traefik.go b/cmd/traefik/traefik.go index 62d15e78d..0559fbb20 100644 --- a/cmd/traefik/traefik.go +++ b/cmd/traefik/traefik.go @@ -504,24 +504,30 @@ func registerMetricClients(metricsConfig *types.Metrics) []metrics.Registry { logger := log.With().Str(logs.MetricsProviderName, "datadog").Logger() registries = append(registries, metrics.RegisterDatadog(logger.WithContext(context.Background()), metricsConfig.Datadog)) - logger.Debug().Msgf("Configured Datadog metrics: pushing to %s once every %s", - metricsConfig.Datadog.Address, metricsConfig.Datadog.PushInterval) + logger.Debug(). + Str("address", metricsConfig.Datadog.Address). + Str("pushInterval", metricsConfig.Datadog.PushInterval.String()). + Msgf("Configured Datadog metrics") } if metricsConfig.StatsD != nil { logger := log.With().Str(logs.MetricsProviderName, "statsd").Logger() registries = append(registries, metrics.RegisterStatsd(logger.WithContext(context.Background()), metricsConfig.StatsD)) - logger.Debug().Msgf("Configured StatsD metrics: pushing to %s once every %s", - metricsConfig.StatsD.Address, metricsConfig.StatsD.PushInterval) + logger.Debug(). + Str("address", metricsConfig.StatsD.Address). + Str("pushInterval", metricsConfig.StatsD.PushInterval.String()). + Msg("Configured StatsD metrics") } if metricsConfig.InfluxDB != nil { logger := log.With().Str(logs.MetricsProviderName, "influxdb").Logger() registries = append(registries, metrics.RegisterInfluxDB(logger.WithContext(context.Background()), metricsConfig.InfluxDB)) - logger.Debug().Msgf("Configured InfluxDB metrics: pushing to %s once every %s", - metricsConfig.InfluxDB.Address, metricsConfig.InfluxDB.PushInterval) + logger.Debug(). + Str("address", metricsConfig.InfluxDB.Address). + Str("pushInterval", metricsConfig.InfluxDB.PushInterval.String()). + Msg("Configured InfluxDB metrics") } if metricsConfig.InfluxDB2 != nil { @@ -530,8 +536,25 @@ func registerMetricClients(metricsConfig *types.Metrics) []metrics.Registry { influxDB2Register := metrics.RegisterInfluxDB2(logger.WithContext(context.Background()), metricsConfig.InfluxDB2) if influxDB2Register != nil { registries = append(registries, influxDB2Register) - logger.Debug().Msgf("Configured InfluxDB v2 metrics: pushing to %s (%s org/%s bucket) once every %s", - metricsConfig.InfluxDB2.Address, metricsConfig.InfluxDB2.Org, metricsConfig.InfluxDB2.Bucket, metricsConfig.InfluxDB2.PushInterval) + logger.Debug(). + Str("address", metricsConfig.InfluxDB2.Address). + Str("bucket", metricsConfig.InfluxDB2.Bucket). + Str("organization", metricsConfig.InfluxDB2.Org). + Str("pushInterval", metricsConfig.InfluxDB2.PushInterval.String()). + Msg("Configured InfluxDB v2 metrics") + } + } + + if metricsConfig.OpenTelemetry != nil { + logger := log.With().Str(logs.MetricsProviderName, "openTelemetry").Logger() + + openTelemetryRegistry := metrics.RegisterOpenTelemetry(logger.WithContext(context.Background()), metricsConfig.OpenTelemetry) + if openTelemetryRegistry != nil { + registries = append(registries, openTelemetryRegistry) + logger.Debug(). + Str("address", metricsConfig.OpenTelemetry.Address). + Str("pushInterval", metricsConfig.OpenTelemetry.PushInterval.String()). + Msg("Configured OpenTelemetry metrics") } } @@ -617,6 +640,14 @@ func setupTracing(conf *static.Tracing) *tracing.Tracing { } } + 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{} diff --git a/docs/content/observability/metrics/opentelemetry.md b/docs/content/observability/metrics/opentelemetry.md new file mode 100644 index 000000000..e3abed40a --- /dev/null +++ b/docs/content/observability/metrics/opentelemetry.md @@ -0,0 +1,353 @@ +--- +title: "Traefik OpenTelemetry Documentation" +description: "Traefik supports several metrics backends, including OpenTelemetry. Learn how to implement it for observability in Traefik Proxy. Read the technical documentation." +--- + +# OpenTelemetry + +To enable the OpenTelemetry: + +```yaml tab="File (YAML)" +metrics: + openTelemetry: {} +``` + +```toml tab="File (TOML)" +[metrics] + [metrics.openTelemetry] +``` + +```bash tab="CLI" +--metrics.openTelemetry=true +``` + +!!! info "The OpenTelemetry exporter will export metrics to the collector by using HTTP by default, see the [gRPC Section](#grpc-configuration) to use gRPC." + +#### `address` + +_Required, Default="localhost:4318", Format="`:`"_ + +Address of the OpenTelemetry Collector to send metrics to. + +```yaml tab="File (YAML)" +metrics: + openTelemetry: + address: localhost:4318 +``` + +```toml tab="File (TOML)" +[metrics] + [metrics.openTelemetry] + address = "localhost:4318" +``` + +```bash tab="CLI" +--metrics.openTelemetry.address=localhost:4318 +``` + +#### `addEntryPointsLabels` + +_Optional, Default=true_ + +Enable metrics on entry points. + +```yaml tab="File (YAML)" +metrics: + openTelemetry: + addEntryPointsLabels: true +``` + +```toml tab="File (TOML)" +[metrics] + [metrics.openTelemetry] + addEntryPointsLabels = true +``` + +```bash tab="CLI" +--metrics.openTelemetry.addEntryPointsLabels=true +``` + +#### `addRoutersLabels` + +_Optional, Default=false_ + +Enable metrics on routers. + +```yaml tab="File (YAML)" +metrics: + openTelemetry: + addRoutersLabels: true +``` + +```toml tab="File (TOML)" +[metrics] + [metrics.openTelemetry] + addRoutersLabels = true +``` + +```bash tab="CLI" +--metrics.openTelemetry.addRoutersLabels=true +``` + +#### `addServicesLabels` + +_Optional, Default=true_ + +Enable metrics on services. + +```yaml tab="File (YAML)" +metrics: + openTelemetry: + addServicesLabels: true +``` + +```toml tab="File (TOML)" +[metrics] + [metrics.openTelemetry] + addServicesLabels = true +``` + +```bash tab="CLI" +--metrics.openTelemetry.addServicesLabels=true +``` + +#### `explicitBoundaries` + +_Optional, Default=".005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10"_ + +Explicit boundaries for Histogram data points. + +```yaml tab="File (YAML)" +metrics: + openTelemetry: + explicitBoundaries: + - 0.1 + - 0.3 + - 1.2 + - 5.0 +``` + +```toml tab="File (TOML)" +[metrics] + [metrics.openTelemetry] + explicitBoundaries = [0.1,0.3,1.2,5.0] +``` + +```bash tab="CLI" +--metrics.openTelemetry.explicitBoundaries=0.1,0.3,1.2,5.0 +``` + +#### `headers` + +_Optional, Default={}_ + +Additional headers sent with metrics by the reporter to the OpenTelemetry Collector. + +```yaml tab="File (YAML)" +metrics: + openTelemetry: + headers: + foo: bar + baz: buz +``` + +```toml tab="File (TOML)" +[metrics] + [metrics.openTelemetry.headers] + foo = "bar" + baz = "buz" +``` + +```bash tab="CLI" +--metrics.openTelemetry.headers.foo=bar --metrics.openTelemetry.headers.baz=buz +``` + +#### `insecure` + +_Optional, Default=false_ + +Allows reporter to send metrics to the OpenTelemetry Collector without using a secured protocol. + +```yaml tab="File (YAML)" +metrics: + openTelemetry: + insecure: true +``` + +```toml tab="File (TOML)" +[metrics] + [metrics.openTelemetry] + insecure = true +``` + +```bash tab="CLI" +--metrics.openTelemetry.insecure=true +``` + +#### `pushInterval` + +_Optional, Default=10s_ + +Interval at which metrics are sent to the OpenTelemetry Collector. + +```yaml tab="File (YAML)" +metrics: + openTelemetry: + pushInterval: 10s +``` + +```toml tab="File (TOML)" +[metrics] + [metrics.openTelemetry] + pushInterval = "10s" +``` + +```bash tab="CLI" +--metrics.openTelemetry.pushInterval=10s +``` + +#### `path` + +_Required, Default="/v1/traces"_ + +Allows to override the default URL path used for sending metrics. +This option has no effect when using gRPC transport. + +```yaml tab="File (YAML)" +metrics: + openTelemetry: + path: /foo/v1/traces +``` + +```toml tab="File (TOML)" +[metrics] + [metrics.openTelemetry] + path = "/foo/v1/traces" +``` + +```bash tab="CLI" +--metrics.openTelemetry.path=/foo/v1/traces +``` + +#### `tls` + +_Optional_ + +Defines the TLS configuration used by the reporter to send metrics 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)" +metrics: + openTelemetry: + tls: + ca: path/to/ca.crt +``` + +```toml tab="File (TOML)" +[metrics.openTelemetry.tls] + ca = "path/to/ca.crt" +``` + +```bash tab="CLI" +--metrics.openTelemetry.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)" +metrics: + openTelemetry: + tls: + cert: path/to/foo.cert + key: path/to/foo.key +``` + +```toml tab="File (TOML)" +[metrics.openTelemetry.tls] + cert = "path/to/foo.cert" + key = "path/to/foo.key" +``` + +```bash tab="CLI" +--metrics.openTelemetry.tls.cert=path/to/foo.cert +--metrics.openTelemetry.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)" +metrics: + openTelemetry: + tls: + cert: path/to/foo.cert + key: path/to/foo.key +``` + +```toml tab="File (TOML)" +[metrics.openTelemetry.tls] + cert = "path/to/foo.cert" + key = "path/to/foo.key" +``` + +```bash tab="CLI" +--metrics.openTelemetry.tls.cert=path/to/foo.cert +--metrics.openTelemetry.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)" +metrics: + openTelemetry: + tls: + insecureSkipVerify: true +``` + +```toml tab="File (TOML)" +[metrics.openTelemetry.tls] + insecureSkipVerify = true +``` + +```bash tab="CLI" +--metrics.openTelemetry.tls.insecureSkipVerify=true +``` + +#### gRPC configuration + +This instructs the reporter to send metrics to the OpenTelemetry Collector using gRPC. + +```yaml tab="File (YAML)" +metrics: + openTelemetry: + grpc: {} +``` + +```toml tab="File (TOML)" +[metrics] + [metrics.openTelemetry.grpc] +``` + +```bash tab="CLI" +--metrics.openTelemetry.grpc=true +``` diff --git a/docs/content/observability/tracing/opentelemetry.md b/docs/content/observability/tracing/opentelemetry.md new file mode 100644 index 000000000..d39e09b58 --- /dev/null +++ b/docs/content/observability/tracing/opentelemetry.md @@ -0,0 +1,246 @@ +--- +title: "Traefik OpenTelemetry Documentation" +description: "Traefik supports several tracing backends, including OpenTelemetry. Learn how to implement it for observability in Traefik Proxy. Read the technical documentation." +--- + +# OpenTelemetry + +To enable the OpenTelemetry tracer: + +```yaml tab="File (YAML)" +tracing: + openTelemetry: {} +``` + +```toml tab="File (TOML)" +[tracing] + [tracing.openTelemetry] +``` + +```bash tab="CLI" +--tracing.openTelemetry=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 "Trace sampling" + + 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` + +_Required, Default="localhost:4318", Format="`:`"_ + +Address of the OpenTelemetry Collector to send spans to. + +```yaml tab="File (YAML)" +tracing: + openTelemetry: + address: localhost:4318 +``` + +```toml tab="File (TOML)" +[tracing] + [tracing.openTelemetry] + address = "localhost:4318" +``` + +```bash tab="CLI" +--tracing.openTelemetry.address=localhost:4318 +``` + +#### `headers` + +_Optional, Default={}_ + +Additional headers sent with spans by the reporter to the OpenTelemetry Collector. + +```yaml tab="File (YAML)" +tracing: + openTelemetry: + headers: + foo: bar + baz: buz +``` + +```toml tab="File (TOML)" +[tracing] + [tracing.openTelemetry.headers] + foo = "bar" + baz = "buz" +``` + +```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 +``` + +#### `tls` + +_Optional_ + +Defines the 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: + openTelemetry: + tls: + ca: path/to/ca.crt +``` + +```toml tab="File (TOML)" +[tracing.openTelemetry.tls] + ca = "path/to/ca.crt" +``` + +```bash tab="CLI" +--tracing.openTelemetry.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: + openTelemetry: + tls: + cert: path/to/foo.cert + key: path/to/foo.key +``` + +```toml tab="File (TOML)" +[tracing.openTelemetry.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 +``` + +##### `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: + openTelemetry: + tls: + cert: path/to/foo.cert + key: path/to/foo.key +``` + +```toml tab="File (TOML)" +[tracing.openTelemetry.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 +``` + +##### `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: + openTelemetry: + tls: + insecureSkipVerify: true +``` + +```toml tab="File (TOML)" +[tracing.openTelemetry.tls] + insecureSkipVerify = true +``` + +```bash tab="CLI" +--tracing.openTelemetry.tls.insecureSkipVerify=true +``` + +#### gRPC configuration + +_Optional_ + +This instructs the reporter to send spans to the OpenTelemetry Collector using gRPC. + +```yaml tab="File (YAML)" +tracing: + openTelemetry: + grpc: {} +``` + +```toml tab="File (TOML)" +[tracing] + [tracing.openTelemetry.grpc] +``` + +```bash tab="CLI" +--tracing.openTelemetry.grpc=true +``` diff --git a/docs/content/reference/static-configuration/cli-ref.md b/docs/content/reference/static-configuration/cli-ref.md index 3b40890e7..a79447131 100644 --- a/docs/content/reference/static-configuration/cli-ref.md +++ b/docs/content/reference/static-configuration/cli-ref.md @@ -357,6 +357,51 @@ InfluxDB v2 push interval. (Default: ```10```) `--metrics.influxdb2.token`: InfluxDB v2 access token. +`--metrics.opentelemetry`: +OpenTelemetry metrics exporter type. (Default: ```false```) + +`--metrics.opentelemetry.addentrypointslabels`: +Enable metrics on entry points. (Default: ```true```) + +`--metrics.opentelemetry.address`: +Address (host:port) of the collector endpoint. (Default: ```localhost:4318```) + +`--metrics.opentelemetry.addrouterslabels`: +Enable metrics on routers. (Default: ```false```) + +`--metrics.opentelemetry.addserviceslabels`: +Enable metrics on services. (Default: ```true```) + +`--metrics.opentelemetry.explicitboundaries`: +Boundaries for latency metrics. (Default: ```0.005000, 0.010000, 0.025000, 0.050000, 0.100000, 0.250000, 0.500000, 1.000000, 2.500000, 5.000000, 10.000000```) + +`--metrics.opentelemetry.grpc`: +gRPC specific configuration for the OpenTelemetry collector. (Default: ```true```) + +`--metrics.opentelemetry.headers.`: +Headers sent with payload. + +`--metrics.opentelemetry.insecure`: +Disables client transport security for the exporter. (Default: ```false```) + +`--metrics.opentelemetry.path`: +Set the URL path of the collector endpoint. + +`--metrics.opentelemetry.pushinterval`: +Period between calls to collect a checkpoint. (Default: ```10```) + +`--metrics.opentelemetry.tls.ca`: +TLS CA + +`--metrics.opentelemetry.tls.cert`: +TLS cert + +`--metrics.opentelemetry.tls.insecureskipverify`: +TLS insecure skip verify (Default: ```false```) + +`--metrics.opentelemetry.tls.key`: +TLS key + `--metrics.prometheus`: Prometheus metrics exporter type. (Default: ```false```) @@ -1095,6 +1140,36 @@ 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.`: +Defines additional headers to be sent with the payloads. + +`--tracing.opentelemetry.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`: +TLS CA + +`--tracing.opentelemetry.tls.cert`: +TLS cert + +`--tracing.opentelemetry.tls.insecureskipverify`: +TLS insecure skip verify (Default: ```false```) + +`--tracing.opentelemetry.tls.key`: +TLS key + `--tracing.servicename`: Set the name for this service. (Default: ```traefik```) diff --git a/docs/content/reference/static-configuration/env-ref.md b/docs/content/reference/static-configuration/env-ref.md index bbcf2459d..41bf8c6bf 100644 --- a/docs/content/reference/static-configuration/env-ref.md +++ b/docs/content/reference/static-configuration/env-ref.md @@ -357,6 +357,51 @@ InfluxDB retention policy used when protocol is http. `TRAEFIK_METRICS_INFLUXDB_USERNAME`: InfluxDB username (only with http). +`TRAEFIK_METRICS_OPENTELEMETRY`: +OpenTelemetry metrics exporter type. (Default: ```false```) + +`TRAEFIK_METRICS_OPENTELEMETRY_ADDENTRYPOINTSLABELS`: +Enable metrics on entry points. (Default: ```true```) + +`TRAEFIK_METRICS_OPENTELEMETRY_ADDRESS`: +Address (host:port) of the collector endpoint. (Default: ```localhost:4318```) + +`TRAEFIK_METRICS_OPENTELEMETRY_ADDROUTERSLABELS`: +Enable metrics on routers. (Default: ```false```) + +`TRAEFIK_METRICS_OPENTELEMETRY_ADDSERVICESLABELS`: +Enable metrics on services. (Default: ```true```) + +`TRAEFIK_METRICS_OPENTELEMETRY_EXPLICITBOUNDARIES`: +Boundaries for latency metrics. (Default: ```0.005000, 0.010000, 0.025000, 0.050000, 0.100000, 0.250000, 0.500000, 1.000000, 2.500000, 5.000000, 10.000000```) + +`TRAEFIK_METRICS_OPENTELEMETRY_GRPC`: +gRPC specific configuration for the OpenTelemetry collector. (Default: ```true```) + +`TRAEFIK_METRICS_OPENTELEMETRY_HEADERS_`: +Headers sent with payload. + +`TRAEFIK_METRICS_OPENTELEMETRY_INSECURE`: +Disables client transport security for the exporter. (Default: ```false```) + +`TRAEFIK_METRICS_OPENTELEMETRY_PATH`: +Set the URL path of the collector endpoint. + +`TRAEFIK_METRICS_OPENTELEMETRY_PUSHINTERVAL`: +Period between calls to collect a checkpoint. (Default: ```10```) + +`TRAEFIK_METRICS_OPENTELEMETRY_TLS_CA`: +TLS CA + +`TRAEFIK_METRICS_OPENTELEMETRY_TLS_CERT`: +TLS cert + +`TRAEFIK_METRICS_OPENTELEMETRY_TLS_INSECURESKIPVERIFY`: +TLS insecure skip verify (Default: ```false```) + +`TRAEFIK_METRICS_OPENTELEMETRY_TLS_KEY`: +TLS key + `TRAEFIK_METRICS_PROMETHEUS`: Prometheus metrics exporter type. (Default: ```false```) @@ -1095,6 +1140,36 @@ 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_`: +Defines additional headers to be sent with the payloads. + +`TRAEFIK_TRACING_OPENTELEMETRY_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`: +TLS CA + +`TRAEFIK_TRACING_OPENTELEMETRY_TLS_CERT`: +TLS cert + +`TRAEFIK_TRACING_OPENTELEMETRY_TLS_INSECURESKIPVERIFY`: +TLS insecure skip verify (Default: ```false```) + +`TRAEFIK_TRACING_OPENTELEMETRY_TLS_KEY`: +TLS key + `TRAEFIK_TRACING_SERVICENAME`: Set the name for this service. (Default: ```traefik```) diff --git a/docs/content/reference/static-configuration/file.toml b/docs/content/reference/static-configuration/file.toml index 2c800f808..73bf8f838 100644 --- a/docs/content/reference/static-configuration/file.toml +++ b/docs/content/reference/static-configuration/file.toml @@ -307,6 +307,25 @@ [metrics.influxDB2.additionalLabels] name0 = "foobar" name1 = "foobar" + [metrics.openTelemetry] + address = "foobar" + addEntryPointsLabels = true + addRoutersLabels = true + addServicesLabels = true + pushInterval = "42s" + path = "foobar" + explicitBoundaries = [42.0, 42.0] + insecure = true + [metrics.openTelemetry.headers] + name0 = "foobar" + name1 = "foobar" + [metrics.openTelemetry.tls] + ca = "foobar" + caOptional = true + cert = "foobar" + insecureSkipVerify = true + key = "foobar" + [metrics.openTelemetry.grpc] [ping] entryPoint = "foobar" @@ -391,6 +410,20 @@ serverURL = "foobar" secretToken = "foobar" serviceEnvironment = "foobar" + [tracing.openTelemetry] + address = "foobar" + insecure = true + path = "foobar" + [tracing.openTelemetry.headers] + name0 = "foobar" + name1 = "foobar" + [tracing.openTelemetry.tls] + ca = "foobar" + caOptional = true + cert = "foobar" + key = "foobar" + insecureSkipVerify = true + [tracing.openTelemetry.grpc] [hostResolver] cnameFlattening = true diff --git a/docs/content/reference/static-configuration/file.yaml b/docs/content/reference/static-configuration/file.yaml index a7a611e27..e84e553d9 100644 --- a/docs/content/reference/static-configuration/file.yaml +++ b/docs/content/reference/static-configuration/file.yaml @@ -335,6 +335,28 @@ metrics: additionalLabels: name0: foobar name1: foobar + openTelemetry: + address: foobar + addEntryPointsLabels: true + addRoutersLabels: true + addServicesLabels: true + explicitBoundaries: + - 42 + - 42 + headers: + name0: foobar + name1: foobar + insecure: true + path: foobar + pushInterval: 42s + tls: + ca: foobar + caOptional: true + cert: foobar + insecureSkipVerify: true + key: foobar + grpc: {} + ping: entryPoint: foobar manualRouting: true @@ -417,6 +439,20 @@ tracing: 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: {} hostResolver: cnameFlattening: true resolvConfig: foobar diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 8090daa7a..91b163347 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -157,6 +157,7 @@ nav: - 'Datadog': 'observability/metrics/datadog.md' - 'InfluxDB': 'observability/metrics/influxdb.md' - 'InfluxDB2': 'observability/metrics/influxdb2.md' + - 'OpenTelemetry': 'observability/metrics/opentelemetry.md' - 'Prometheus': 'observability/metrics/prometheus.md' - 'StatsD': 'observability/metrics/statsd.md' - 'Tracing': @@ -167,6 +168,7 @@ nav: - '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' - 'gRPC Examples': 'user-guides/grpc.md' diff --git a/go.mod b/go.mod index 86872dde8..1ecb9fcdc 100644 --- a/go.mod +++ b/go.mod @@ -47,7 +47,7 @@ require ( github.com/lucas-clemente/quic-go v0.28.1 github.com/mailgun/ttlmap v0.0.0-20170619185759-c1c17f74874f github.com/miekg/dns v1.1.50 - github.com/mitchellh/copystructure v1.0.0 + github.com/mitchellh/copystructure v1.2.0 github.com/mitchellh/hashstructure v1.0.0 github.com/mitchellh/mapstructure v1.5.0 github.com/natefinch/lumberjack v0.0.0-20201021141957-47ffae23317c @@ -77,33 +77,45 @@ require ( 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.64.1 + go.opentelemetry.io/otel v1.11.1 + go.opentelemetry.io/otel/bridge/opentracing v1.11.1 + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.33.0 + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.33.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.11.1 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.11.1 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.11.1 + go.opentelemetry.io/otel/metric v0.33.0 + go.opentelemetry.io/otel/sdk v1.11.1 + go.opentelemetry.io/otel/sdk/metric v0.33.0 + go.opentelemetry.io/otel/trace v1.11.1 golang.org/x/exp v0.0.0-20221114191408-850992195362 golang.org/x/mod v0.6.0 golang.org/x/net v0.1.0 golang.org/x/text v0.4.0 - golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 + golang.org/x/time v0.0.0-20220609170525-579cf78fd858 golang.org/x/tools v0.2.0 - google.golang.org/grpc v1.46.0 + google.golang.org/grpc v1.50.1 gopkg.in/DataDog/dd-trace-go.v1 v1.43.1 gopkg.in/fsnotify.v1 v1.4.7 gopkg.in/yaml.v3 v3.0.1 - k8s.io/api v0.22.1 - k8s.io/apiextensions-apiserver v0.21.3 - k8s.io/apimachinery v0.22.1 - k8s.io/client-go v0.22.1 - k8s.io/utils v0.0.0-20210820185131-d34e5cb4466e + k8s.io/api v0.25.0 + k8s.io/apiextensions-apiserver v0.25.0 + k8s.io/apimachinery v0.25.0 + k8s.io/client-go v0.25.0 + k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed mvdan.cc/xurls/v2 v2.1.0 sigs.k8s.io/gateway-api v0.4.0 ) require ( - cloud.google.com/go v0.81.0 // indirect + cloud.google.com/go v0.97.0 // indirect github.com/AlecAivazis/survey/v2 v2.2.3 // indirect github.com/Azure/azure-sdk-for-go v40.3.0+incompatible // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect - github.com/Azure/go-autorest/autorest v0.11.24 // indirect - github.com/Azure/go-autorest/autorest/adal v0.9.18 // indirect + github.com/Azure/go-autorest/autorest v0.11.27 // indirect + github.com/Azure/go-autorest/autorest/adal v0.9.20 // indirect github.com/Azure/go-autorest/autorest/azure/auth v0.5.11 // indirect github.com/Azure/go-autorest/autorest/azure/cli v0.4.5 // indirect github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect @@ -121,6 +133,8 @@ require ( github.com/Microsoft/go-winio v0.5.2 // indirect github.com/Microsoft/hcsshim v0.8.23 // indirect github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87 // indirect + github.com/PuerkitoBio/purell v1.1.1 // indirect + github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/Shopify/sarama v1.23.1 // indirect github.com/VividCortex/gohistogram v1.0.0 // indirect github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 // indirect @@ -165,7 +179,8 @@ require ( 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/evanphx/json-patch v4.11.0+incompatible // indirect + github.com/emicklei/go-restful/v3 v3.8.0 // indirect + github.com/evanphx/json-patch v4.12.0+incompatible // indirect github.com/exoscale/egoscale v0.90.0 // indirect github.com/fatih/color v1.13.0 // indirect github.com/fsnotify/fsnotify v1.5.4 // indirect @@ -173,7 +188,11 @@ require ( github.com/ghodss/yaml v1.0.0 // indirect github.com/go-errors/errors v1.0.1 // indirect github.com/go-logfmt/logfmt v0.5.1 // indirect - github.com/go-logr/logr v0.4.0 // indirect + github.com/go-logr/logr v1.2.3 // 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.19.5 // indirect + github.com/go-openapi/swag v0.19.14 // indirect github.com/go-redis/redis/v8 v8.11.5 // indirect github.com/go-resty/resty/v2 v2.1.1-0.20191201195748-d7b97669fe48 // indirect github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect @@ -182,21 +201,22 @@ require ( github.com/gogo/googleapis v1.4.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v4 v4.2.0 // indirect - github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect + github.com/golang/glog v1.0.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/mock v1.6.0 // indirect github.com/google/btree v1.0.1 // indirect - github.com/google/go-cmp v0.5.8 // indirect + github.com/google/gnostic v0.5.7-v3refs // indirect + github.com/google/go-cmp v0.5.9 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.3.0 // indirect - github.com/googleapis/gax-go/v2 v2.0.5 // indirect - github.com/googleapis/gnostic v0.5.5 // indirect + github.com/googleapis/gax-go/v2 v2.1.0 // indirect github.com/gophercloud/gophercloud v1.0.0 // indirect github.com/gophercloud/utils v0.0.0-20210216074907-f6de111f2eae // indirect github.com/gravitational/trace v1.1.16-0.20220114165159-14a9a7dd6aaf // indirect - github.com/grpc-ecosystem/go-grpc-middleware v1.2.2 // indirect + github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 // indirect github.com/hashicorp/consul/sdk v0.10.0 // indirect github.com/hashicorp/cronexpr v1.1.1 // indirect @@ -237,6 +257,7 @@ require ( 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 github.com/mailgun/timetools v0.0.0-20141028012446-7e6055773c51 // indirect @@ -256,7 +277,7 @@ require ( github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-ps v1.0.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect - github.com/mitchellh/reflectwalk v1.0.1 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/moby/buildkit v0.8.2-0.20210401015549-df49b648c8bf // indirect github.com/moby/locker v1.0.1 // indirect github.com/moby/sys/mount v0.2.0 // indirect @@ -265,6 +286,7 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/morikuni/aec v1.0.0 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 // indirect github.com/nrdcg/auroradns v1.1.0 // indirect github.com/nrdcg/desec v0.6.0 // indirect @@ -300,7 +322,7 @@ require ( github.com/softlayer/softlayer-go v1.0.6 // indirect github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e // indirect github.com/spf13/cast v1.3.1 // indirect - github.com/spf13/cobra v1.2.1 // indirect + github.com/spf13/cobra v1.4.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/objx v0.5.0 // indirect github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.490 // indirect @@ -325,10 +347,13 @@ require ( go.etcd.io/etcd/client/pkg/v3 v3.5.4 // indirect go.etcd.io/etcd/client/v3 v3.5.4 // indirect go.opencensus.io v0.23.0 // indirect - go.uber.org/atomic v1.7.0 // indirect - go.uber.org/multierr v1.6.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.11.1 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.33.0 // indirect + go.opentelemetry.io/proto/otlp v0.19.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.8.0 // indirect go.uber.org/ratelimit v0.2.0 // indirect - go.uber.org/zap v1.18.1 // indirect + go.uber.org/zap v1.21.0 // indirect go4.org/intern v0.0.0-20211027215823-ae77deb06f29 // indirect go4.org/unsafe/assume-no-moving-gc v0.0.0-20220617031537-928513b29760 // indirect golang.org/x/crypto v0.1.0 // indirect @@ -338,10 +363,10 @@ require ( golang.org/x/sys v0.1.0 // indirect golang.org/x/term v0.1.0 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect - google.golang.org/api v0.44.0 // indirect + google.golang.org/api v0.57.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20211021150943-2b146023228c // indirect - google.golang.org/protobuf v1.28.0 // indirect + google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21 // indirect + google.golang.org/protobuf v1.28.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.66.6 // indirect gopkg.in/ns1/ns1-go.v2 v2.6.5 // indirect @@ -350,11 +375,12 @@ require ( gopkg.in/yaml.v2 v2.4.0 // indirect howett.net/plist v0.0.0-20181124034731-591f970eefbb // indirect inet.af/netaddr v0.0.0-20220617031823-097006376321 // indirect - k8s.io/klog/v2 v2.10.0 // indirect - k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e // indirect + k8s.io/klog/v2 v2.70.1 // indirect + k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 // indirect nhooyr.io/websocket v1.8.7 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect - sigs.k8s.io/yaml v1.2.0 // indirect + sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect ) // Containous forks @@ -371,3 +397,5 @@ replace github.com/jaguilar/vt100 => github.com/tonistiigi/vt100 v0.0.0-20190402 // ambiguous import: found package github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/http in multiple modules // tencentcloud uses monorepo with multimodule but the go.mod files are incomplete. exclude github.com/tencentcloud/tencentcloud-sdk-go v3.0.83+incompatible + +// replace github.com/go-logr/logr => github.com/go-logr/logr v0.4.0 diff --git a/go.sum b/go.sum index 25a719ffa..20e5707d6 100644 --- a/go.sum +++ b/go.sum @@ -24,8 +24,15 @@ cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKP cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= -cloud.google.com/go v0.81.0 h1:at8Tk2zUz63cLPR0JPWm5vp77pEZmzxEQBEfRKn1VV8= cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0 h1:3DXvAyifywvq64LfkKaMOmkWPS1CikIQdMe2lY9vxU8= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= @@ -70,8 +77,9 @@ github.com/Azure/go-autorest/autorest v0.10.0/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUd github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= github.com/Azure/go-autorest/autorest v0.11.12/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw= github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= -github.com/Azure/go-autorest/autorest v0.11.24 h1:1fIGgHKqVm54KIPT+q8Zmd1QlVsmHqeUGso5qm2BqqE= github.com/Azure/go-autorest/autorest v0.11.24/go.mod h1:G6kyRlFnTuSbEYkQGawPfsCswgme4iYf6rfSKUDzbCc= +github.com/Azure/go-autorest/autorest v0.11.27 h1:F3R3q42aWytozkV8ihzcgMO4OA4cuqr3bNlsEuF6//A= +github.com/Azure/go-autorest/autorest v0.11.27/go.mod h1:7l8ybrIdUmGqZMTD0sRtAr8NvbHjfofbf8RSP2q7w7U= github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= @@ -79,8 +87,9 @@ github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMl github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= -github.com/Azure/go-autorest/autorest/adal v0.9.18 h1:kLnPsRjzZZUF3K5REu/Kc+qMQrvuza2bwSnNdhmzLfQ= github.com/Azure/go-autorest/autorest/adal v0.9.18/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ= +github.com/Azure/go-autorest/autorest/adal v0.9.20 h1:gJ3E98kMpFB1MFqQCvA1yFab8vthOeD4VlFRQULxahg= +github.com/Azure/go-autorest/autorest/adal v0.9.20/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ= github.com/Azure/go-autorest/autorest/azure/auth v0.4.2/go.mod h1:90gmfKdlmKgfjUpnCEpOJzsUEjrWDSLwHIG73tSXddM= github.com/Azure/go-autorest/autorest/azure/auth v0.5.11 h1:P6bYXFoao05z5uhOQzbC3Qd8JqF3jUoocoTeIxkp2cA= github.com/Azure/go-autorest/autorest/azure/auth v0.5.11/go.mod h1:84w/uV8E37feW2NCJ08uT9VBfjfUHpgLVnG2InYD6cg= @@ -95,8 +104,9 @@ github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxB github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= -github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk= github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.2 h1:PGN4EDXnuQbojHbU0UWoNvmu9AGVwYHG9/fkDYhtAfw= +github.com/Azure/go-autorest/autorest/mocks v0.4.2/go.mod h1:Vy7OitM9Kei0i1Oj+LvyAWMXJHeKH1MVlzFugfVrmyU= github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= github.com/Azure/go-autorest/autorest/to v0.4.0 h1:oXVqrxakqqV1UZdSazDOPOLvOIz+XA683u8EctwboHk= github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE= @@ -175,8 +185,10 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87 h1:xPMsUicZ3iosVPSIP7bW5EcGUzjiiMl1OYTe14y/R24= github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87/go.mod h1:iGLljf5n9GjT6kc0HBvyI1nOKnGQbNB66VzSNbK5iks= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= 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= @@ -480,6 +492,7 @@ github.com/cpu/goacmedns v0.1.1/go.mod h1:MuaouqEhPAHxsbqjgnck5zeghuwBP1dLnPoobe github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= @@ -608,6 +621,8 @@ github.com/elazarl/goproxy v0.0.0-20191011121108-aa519ddbe484/go.mod h1:Ro8st/El github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful/v3 v3.8.0 h1:eCZ8ulSerjdAiaNpF7GxXIE7ZCMo1moN1qX+S609eVw= +github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -624,8 +639,9 @@ github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch v4.11.0+incompatible h1:glyUF9yIYtMHzn8xaKw5rMhdWcwsYV8dZHIq5567/xs= github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= +github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/exoscale/egoscale v0.90.0 h1:DZBXVU3iHqu5Ju5lQ5jWVlPo0IpI98SUo8Aa1UQVrmo= github.com/exoscale/egoscale v0.90.0/go.mod h1:wyXE5zrnFynMXA0jMhwQqSe24CfUhmBk2WI5wFZcq6Y= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= @@ -695,17 +711,24 @@ github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNV github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc= 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.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +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= github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM= github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= @@ -713,6 +736,7 @@ github.com/go-openapi/spec v0.19.5/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHK github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= @@ -784,8 +808,9 @@ github.com/golang-jwt/jwt/v4 v4.1.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzw github.com/golang-jwt/jwt/v4 v4.2.0 h1:besgBTC8w8HjP6NzQdxwKH9Z5oQMZ24ThTrHp3cZ8eU= github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= 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= @@ -826,6 +851,7 @@ github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw github.com/golang/protobuf v1.5.2/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.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= 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= @@ -836,6 +862,8 @@ github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/certificate-transparency-go v1.0.21 h1:Yf1aXowfZ2nuboBsg7iYGLmwsOARdV86pfH3g95wXmE= github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= +github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54= +github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -849,8 +877,8 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 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 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= -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-containerregistry v0.0.0-20191015185424-71da34e4d9b3/go.mod h1:ZXFeSndFcK4vB1NR4voH1Zm38K7ViUNiYtfIBDxrwf0= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-github/v28 v28.1.1 h1:kORf5ekX5qwXO2mGzXXOjMe/g6ap8ahVe0sBEulhSxo= @@ -869,6 +897,7 @@ github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -882,6 +911,8 @@ github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= @@ -895,15 +926,15 @@ github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.1.0 h1:6DWmvNpomjL1+3liNSZbVns3zsYzzCjm6pRBO1tLeso= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= github.com/googleapis/gnostic v0.0.0-20170426233943-68f4ded48ba9/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= -github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= github.com/gophercloud/gophercloud v0.15.1-0.20210202035223-633d73521055/go.mod h1:wRtmUelyIIv3CSSDI47aUwbs075O6i+LY+pXsKCBsb4= @@ -929,13 +960,16 @@ github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:Fecb github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.2.0/go.mod h1:mJzapYve32yjrKlk9GbyCZHuPgZsrbyIbyKhSzOpg6s= -github.com/grpc-ecosystem/go-grpc-middleware v1.2.2 h1:FlFbCRLd5Jr4iYXZufAvgWN6Ao0JrI5chLINnUXDDr0= github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 h1:BZHcxBETFHIdVyhyEfOvn/RdU/QGdLI4y34qQGjGWO0= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 h1:MJG/KsmcqMwFAkh8mTnAwhyKoB+sTAnY4CACC110tbU= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw= github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw= @@ -1249,8 +1283,9 @@ github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0Q github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= -github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= +github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailgun/multibuf v0.1.2 h1:QE9kE27lK6LFZB4aYNVtUPlWVHVCT0zpgUr2uoq/+jk= github.com/mailgun/multibuf v0.1.2/go.mod h1:E+sUhIy69qgT6EM57kCPdUTlHnjTuxQBO/yf6af9Hes= github.com/mailgun/timetools v0.0.0-20141028012446-7e6055773c51 h1:Kg/NPZLLC3aAFr1YToMs98dbCdhootQ1hZIvZU28hAQ= @@ -1326,8 +1361,9 @@ github.com/mimuret/golang-iij-dpf v0.7.1/go.mod h1:IXWYcQVIHYzuM+W7kDWX0mseHDfUo github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= -github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -1358,8 +1394,9 @@ github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQ github.com/mitchellh/pointerstructure v1.0.0 h1:ATSdz4NWrmWPOF1CeCBU4sMCno2hgqdbSrRPFWQSVZI= github.com/mitchellh/pointerstructure v1.0.0/go.mod h1:k4XwG94++jLVsSiTxo7qdIfXA9pj9EAeo0QsNNJOLZ8= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE= github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/moby/buildkit v0.8.2-0.20210401015549-df49b648c8bf h1:dHwWBX8OhYb69qVcT27rFSwzKsn4CRbg0HInQyVh33c= github.com/moby/buildkit v0.8.2-0.20210401015549-df49b648c8bf/go.mod h1:GJcrUlTGFAPlEmPQtbrTsJYn+cy+Jwl7vTZS7jYAoow= github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= @@ -1393,6 +1430,7 @@ github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1 github.com/mrunalp/fileutils v0.0.0-20200520151820-abd8a0e76976/go.mod h1:x8F1gnqOkIEiO4rqoeEEEqQbo7HjGMTvyoq3gej4iT0= github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= @@ -1456,6 +1494,7 @@ 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.1.4 h1:GNapqRSid3zijZ9H77KrgVG4/8KqiyRsxcSxe+7ApXY= 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= @@ -1751,8 +1790,9 @@ github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tL github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= -github.com/spf13/cobra v1.2.1 h1:+KmjbUw1hriSNMF55oPrkZcb27aECyrj8V2ytv7kWDw= github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= +github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q= +github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= @@ -1956,26 +1996,60 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opentelemetry.io/collector/pdata v0.64.1 h1:8E06uHr0nnenGftFwhwdenA88QhVnF4dJam+qVXgdVg= +go.opentelemetry.io/collector/pdata v0.64.1/go.mod h1:IzvXUGQml2mrnvdb8zIlEW3qQs9oFLdD2hLwJdZ+pek= +go.opentelemetry.io/otel v1.11.1 h1:4WLLAmcfkmDk2ukNXJyq3/kiz/3UzCaYq6PskJsaou4= +go.opentelemetry.io/otel v1.11.1/go.mod h1:1nNhXBbWSD0nsL38H6btgnFN2k4i0sNLHNNMZMSbUGE= +go.opentelemetry.io/otel/bridge/opentracing v1.11.1 h1:/ZBsgjXWUpiZ5M9zm+Ft3kuDUGErIGcEJbKRIsFN6jA= +go.opentelemetry.io/otel/bridge/opentracing v1.11.1/go.mod h1:vw9hN4H+G0ek+XQtxP+Mm1McLcmdx2FXHNrWn2bBqxU= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.11.1 h1:X2GndnMCsUPh6CiY2a+frAbNsXaPLbB0soHRYhAZ5Ig= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.11.1/go.mod h1:i8vjiSzbiUC7wOQplijSXMYUpNM93DtlS5CbUT+C6oQ= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.33.0 h1:OT/UjHcjog4A1s1UMCtyehIKS+vpjM5Du0r7KGsH6TE= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.33.0/go.mod h1:0XctNDHEWmiSDIU8NPbJElrK05gBJFcYlGP4FMGo4g4= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.33.0 h1:1SVtGtRsNyGgv1fRfNXfh+sJowIwzF0gkf+61lvTgdg= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.33.0/go.mod h1:ryB27ubOBXsiqfh6MwtSdx5knzbSZtjvPnMMmt3AykQ= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.33.0 h1:NoG4v01cdLZfOeNGBQmSe4f4SeP+fx8I/0qzRgTKsGI= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.33.0/go.mod h1:6anbDXBcTp3Qit87pfFmT0paxTJ8sWRccTNYVywN/H8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.11.1 h1:MEQNafcNCB0uQIti/oHgU7CZpUMYQ7qigBwMVKycHvc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.11.1/go.mod h1:19O5I2U5iys38SsmT2uDJja/300woyzE1KPIQxEUBUc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.11.1 h1:LYyG/f1W/jzAix16jbksJfMQFpOH/Ma6T639pVPMgfI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.11.1/go.mod h1:QrRRQiY3kzAoYPNLP0W/Ikg0gR6V3LMc+ODSxr7yyvg= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.11.1 h1:tFl63cpAAcD9TOU6U8kZU7KyXuSRYAZlbx1C61aaB74= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.11.1/go.mod h1:X620Jww3RajCJXw/unA+8IRTgxkdS7pi+ZwK9b7KUJk= +go.opentelemetry.io/otel/metric v0.33.0 h1:xQAyl7uGEYvrLAiV/09iTJlp1pZnQ9Wl793qbVvED1E= +go.opentelemetry.io/otel/metric v0.33.0/go.mod h1:QlTYc+EnYNq/M2mNk1qDDMRLpqCOj2f/r5c7Fd5FYaI= +go.opentelemetry.io/otel/sdk v1.11.1 h1:F7KmQgoHljhUuJyA+9BiU+EkJfyX5nVVF4wyzWZpKxs= +go.opentelemetry.io/otel/sdk v1.11.1/go.mod h1:/l3FE4SupHJ12TduVjUkZtlfFqDCQJlOlithYrdktys= +go.opentelemetry.io/otel/sdk/metric v0.33.0 h1:oTqyWfksgKoJmbrs2q7O7ahkJzt+Ipekihf8vhpa9qo= +go.opentelemetry.io/otel/sdk/metric v0.33.0/go.mod h1:xdypMeA21JBOvjjzDUtD0kzIcHO/SPez+a8HOzJPGp0= +go.opentelemetry.io/otel/trace v1.11.1 h1:ofxdnzsNrGBYXbP7t7zpUK281+go5rF7dvdIZXF8gdQ= +go.opentelemetry.io/otel/trace v1.11.1/go.mod h1:f/Q9G7vzk5u91PhbmKbg1Qn0rzH1LJ4vbPHFGkTPtOk= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw= +go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= 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 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= 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.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= +go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= go.uber.org/ratelimit v0.2.0 h1:UQE2Bgi7p2B85uP5dC2bbRtig0C+OeNRnNEafLjsLPA= go.uber.org/ratelimit v0.2.0/go.mod h1:YYBV4e4naJvhpitQrWJu1vCpgB7CboMe0qhltKt6mUg= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= -go.uber.org/zap v1.18.1 h1:CSUJ2mjFszzEWt4CdKISEuChVIXGBn3lAPwkRGyVrc4= 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 v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= go4.org/intern v0.0.0-20211027215823-ae77deb06f29 h1:UXLjNohABv4S58tHmeuIZDO6e3mHpW2Dx33gaNt03LE= go4.org/intern v0.0.0-20211027215823-ae77deb06f29/go.mod h1:cS2ma+47FKrLPdXFpr7CuxiTW3eyJbWew4qx0qtQWDA= @@ -2139,6 +2213,7 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -2167,6 +2242,10 @@ golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 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-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/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.0.0-20220909003341-f21342109be1 h1:lxqLZaMad/dJHMFZH0NiNpiEZI/nhgWhe4wgzpE+MuA= golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= @@ -2297,12 +2376,16 @@ golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -2341,8 +2424,8 @@ golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 h1:M73Iuj3xbbb9Uk1DYhzydthsj6oOd6l9bpuFcNoUvTs= -golang.org/x/time v0.0.0-20220224211638-0e9765cccd65/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220609170525-579cf78fd858 h1:Dpdu/EMxGMFgq0CeYMh4fazTD2vtlZRYE7wyynxJb9U= +golang.org/x/time v0.0.0-20220609170525-579cf78fd858/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -2416,6 +2499,8 @@ golang.org/x/tools v0.0.0-20210114065538-d78b04bdf963/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/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.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE= @@ -2458,8 +2543,15 @@ google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34q google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.44.0 h1:URs6qR1lAxDsqWITsQXI4ZkGiYJ5dHtRNiCpfs2OeKA= google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0 h1:4t9zuDlHLcIx0ZEhmXEeFVCRsiOgpgn2QOH9N0MNjPI= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -2526,9 +2618,25 @@ google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20211021150943-2b146023228c h1:FqrtZMB5Wr+/RecOM3uPJNPfWR8Upb5hAPnt7PU6i4k= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211021150943-2b146023228c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21 h1:hrbNEivu7Zn1pxvHk6MBrq9iE22woVILTHqexqBxe6I= +google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= @@ -2559,11 +2667,18 @@ google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA5 google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= -google.golang.org/grpc v1.46.0 h1:oCjezcn6g6A75TGoKYBPgKmVBLexhYLM6MebdrPApP8= +google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.50.1 h1:DS/BukOZWp8s6p4Dt/tOaJaTQyPyOoCcrjroHuCeLzY= +google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= 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= @@ -2578,8 +2693,9 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/DataDog/dd-trace-go.v1 v1.43.1 h1:Dez4VzRQWAI5YXJRBx58BiC0gONGuW/oY4l8fWKzOXY= gopkg.in/DataDog/dd-trace-go.v1 v1.43.1/go.mod h1:YL9g+nlUY7ByCffD5pDytAqy99GNbytRV0EBpKuldM4= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= @@ -2677,10 +2793,12 @@ k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ= k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8= k8s.io/api v0.21.0/go.mod h1:+YbrhBBGgsxbF6o6Kj4KJPJnBmAKuXDeS3E18bgHNVU= k8s.io/api v0.21.3/go.mod h1:hUgeYHUbBp23Ue4qdX9tR8/ANi/g3ehylAqDn9NWVOg= -k8s.io/api v0.22.1 h1:ISu3tD/jRhYfSW8jI/Q1e+lRxkR7w9UwQEZ7FgslrwY= k8s.io/api v0.22.1/go.mod h1:bh13rkTp3F1XEaLGykbyRD2QaTTzPm0e/BMd8ptFONY= -k8s.io/apiextensions-apiserver v0.21.3 h1:+B6biyUWpqt41kz5x6peIsljlsuwvNAp/oFax/j2/aY= +k8s.io/api v0.25.0 h1:H+Q4ma2U/ww0iGB78ijZx6DRByPz6/733jIuFpX70e0= +k8s.io/api v0.25.0/go.mod h1:ttceV1GyV1i1rnmvzT3BST08N6nGt+dudGrquzVQWPk= k8s.io/apiextensions-apiserver v0.21.3/go.mod h1:kl6dap3Gd45+21Jnh6utCx8Z2xxLm8LGDkprcd+KbsE= +k8s.io/apiextensions-apiserver v0.25.0 h1:CJ9zlyXAbq0FIW8CD7HHyozCMBpDSiH7EdrSTCZcZFY= +k8s.io/apiextensions-apiserver v0.25.0/go.mod h1:3pAjZiN4zw7R8aZC5gR0y3/vCkGlAjCazcg1me8iB/E= k8s.io/apimachinery v0.0.0-20180904193909-def12e63c512/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= k8s.io/apimachinery v0.0.0-20190806215851-162a2dabc72f/go.mod h1:+ntn62igV2hyNj7/0brOvXSMONE2KxcePkSxK7/9FFQ= k8s.io/apimachinery v0.0.0-20191004115801-a2eda9f80ab8/go.mod h1:llRdnznGEAqC3DcNm6yEj472xaFVfLM7hnYofMb12tQ= @@ -2690,8 +2808,9 @@ k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRp k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc= k8s.io/apimachinery v0.21.0/go.mod h1:jbreFvJo3ov9rj7eWT7+sYiRx+qZuCYXwWT1bcDswPY= k8s.io/apimachinery v0.21.3/go.mod h1:H/IM+5vH9kZRNJ4l3x/fXP/5bOPJaVP/guptnZPeCFI= -k8s.io/apimachinery v0.22.1 h1:DTARnyzmdHMz7bFWFDDm22AM4pLWTQECMpRTFu2d2OM= k8s.io/apimachinery v0.22.1/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0= +k8s.io/apimachinery v0.25.0 h1:MlP0r6+3XbkUG2itd6vp3oxbtdQLQI94fD5gCS+gnoU= +k8s.io/apimachinery v0.25.0/go.mod h1:qMx9eAk0sZQGsXGu86fab8tZdffHbwUfsvzqKn4mfB0= k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= k8s.io/apiserver v0.20.4/go.mod h1:Mc80thBKOyy7tbvFtB4kJv1kbdD0eIH8k8vianJcbFM= k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q= @@ -2704,8 +2823,9 @@ k8s.io/client-go v0.20.4/go.mod h1:LiMv25ND1gLUdBeYxBIwKpkSC5IsozMMmOOeSJboP+k= k8s.io/client-go v0.20.6/go.mod h1:nNQMnOvEUEsOzRRFIIkdmYOjAZrC8bgq0ExboWSU1I0= k8s.io/client-go v0.21.0/go.mod h1:nNBytTF9qPFDEhoqgEPaarobC8QPae13bElIVHzIglA= k8s.io/client-go v0.21.3/go.mod h1:+VPhCgTsaFmGILxR/7E1N0S+ryO010QBeNCv5JwRGYU= -k8s.io/client-go v0.22.1 h1:jW0ZSHi8wW260FvcXHkIa0NLxFBQszTlhiAVsU5mopw= k8s.io/client-go v0.22.1/go.mod h1:BquC5A4UOo4qVDUtoc04/+Nxp1MeHcVc1HJm1KmG8kk= +k8s.io/client-go v0.25.0 h1:CVWIaCETLMBNiTUta3d5nzRbXvY5Hy9Dpl+VvREpu5E= +k8s.io/client-go v0.25.0/go.mod h1:lxykvypVfKilxhTklov0wz1FoaUZ8X4EwbhS6rpRfN8= k8s.io/code-generator v0.21.3/go.mod h1:K3y0Bv9Cz2cOW2vXUrNZlFbflhuPvuadW6JdnN6gGKo= k8s.io/code-generator v0.22.0/go.mod h1:eV77Y09IopzeXOJzndrDyCI88UBok2h6WxAlBwpxa+o= k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk= @@ -2731,23 +2851,26 @@ k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= 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 h1:R2HDMDJsHVTHA2n4RjwbeYXdOcBymXdX/JRb1v0VGhE= k8s.io/klog/v2 v2.10.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= +k8s.io/klog/v2 v2.70.1 h1:7aaoSdahviPmR+XkS7FyxlkkXs6tHISSG03RxleQAVQ= +k8s.io/klog/v2 v2.70.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= k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE= -k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ0m1343QqxZhR2LJ1OxCYM= k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= +k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 h1:MQ8BAZPZlWk3S9K4a9NCkIFQtZShWqoha7snGixVgEA= +k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1/go.mod h1:C/N6wCaBHeBHkHUesQOQy2/MZqGgMAFPqGsGQLdbZBU= k8s.io/kubernetes v1.11.10/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20210707171843-4b05e18ac7d9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20210722164352-7f3ee0f31471/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20210820185131-d34e5cb4466e h1:ldQh+neBabomh7+89dTpiFAB8tGdfVmuIzAHbvtl+9I= k8s.io/utils v0.0.0-20210820185131-d34e5cb4466e/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed h1:jAne/RjBTyawwAy0utX5eqigAwz/lQhTmy+Hr/Cpue4= +k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM= mvdan.cc/xurls/v2 v2.1.0 h1:KaMb5GLhlcSX+e+qhbRJODnUUBvlw01jt4yrjFIHAuA= mvdan.cc/xurls/v2 v2.1.0/go.mod h1:5GrSd9rOnKOpZaji1OZLYL/yeAAtGDlo/cFe+8K5n8E= @@ -2765,15 +2888,19 @@ sigs.k8s.io/controller-runtime v0.9.6/go.mod h1:q6PpkM5vqQubEKUKOM6qr06oXGzOBcCb sigs.k8s.io/controller-tools v0.6.2/go.mod h1:oaeGpjXn6+ZSEIQkUe/+3I40PNiDYp9aeawbt3xTgJ8= sigs.k8s.io/gateway-api v0.4.0 h1:07IJkTt21NetZTHtPKJk2I4XIgDN4BAlTIq1wK7V11o= sigs.k8s.io/gateway-api v0.4.0/go.mod h1:r3eiNP+0el+NTLwaTfOrCNXy8TukC+dIM3ggc+fbNWk= +sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k= +sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.0.3/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.1.0/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno= sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= -sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/pkg/config/static/static_config.go b/pkg/config/static/static_config.go index 3ab86cdff..ce17087c0 100644 --- a/pkg/config/static/static_config.go +++ b/pkg/config/static/static_config.go @@ -35,6 +35,7 @@ import ( "github.com/traefik/traefik/v2/pkg/tracing/haystack" "github.com/traefik/traefik/v2/pkg/tracing/instana" "github.com/traefik/traefik/v2/pkg/tracing/jaeger" + "github.com/traefik/traefik/v2/pkg/tracing/opentelemetry" "github.com/traefik/traefik/v2/pkg/tracing/zipkin" "github.com/traefik/traefik/v2/pkg/types" ) @@ -169,14 +170,15 @@ 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" export:"true" label:"allowEmpty" file:"allowEmpty"` - Zipkin *zipkin.Config `description:"Settings for Zipkin." json:"zipkin,omitempty" toml:"zipkin,omitempty" yaml:"zipkin,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"` - Datadog *datadog.Config `description:"Settings for Datadog." json:"datadog,omitempty" toml:"datadog,omitempty" yaml:"datadog,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"` - Instana *instana.Config `description:"Settings for Instana." json:"instana,omitempty" toml:"instana,omitempty" yaml:"instana,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"` - Haystack *haystack.Config `description:"Settings for Haystack." json:"haystack,omitempty" toml:"haystack,omitempty" yaml:"haystack,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"` - Elastic *elastic.Config `description:"Settings for Elastic." json:"elastic,omitempty" toml:"elastic,omitempty" yaml:"elastic,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"` + 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" export:"true" label:"allowEmpty" file:"allowEmpty"` + Zipkin *zipkin.Config `description:"Settings for Zipkin." json:"zipkin,omitempty" toml:"zipkin,omitempty" yaml:"zipkin,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"` + Datadog *datadog.Config `description:"Settings for Datadog." json:"datadog,omitempty" toml:"datadog,omitempty" yaml:"datadog,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"` + Instana *instana.Config `description:"Settings for Instana." json:"instana,omitempty" toml:"instana,omitempty" yaml:"instana,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"` + Haystack *haystack.Config `description:"Settings for Haystack." json:"haystack,omitempty" toml:"haystack,omitempty" yaml:"haystack,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"` + Elastic *elastic.Config `description:"Settings for Elastic." json:"elastic,omitempty" toml:"elastic,omitempty" yaml:"elastic,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"` + OpenTelemetry *opentelemetry.Config `description:"Settings for OpenTelemetry." json:"openTelemetry,omitempty" toml:"openTelemetry,omitempty" yaml:"openTelemetry,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"` } // SetDefaults sets the default values. diff --git a/pkg/metrics/opentelemetry.go b/pkg/metrics/opentelemetry.go new file mode 100644 index 000000000..328f6fc54 --- /dev/null +++ b/pkg/metrics/opentelemetry.go @@ -0,0 +1,422 @@ +package metrics + +import ( + "context" + "fmt" + "net" + "strings" + "sync" + "time" + + "github.com/go-kit/kit/metrics" + "github.com/rs/zerolog/log" + "github.com/traefik/traefik/v2/pkg/types" + "github.com/traefik/traefik/v2/pkg/version" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc" + "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp" + "go.opentelemetry.io/otel/metric" + "go.opentelemetry.io/otel/metric/global" + "go.opentelemetry.io/otel/metric/instrument" + "go.opentelemetry.io/otel/metric/instrument/asyncfloat64" + "go.opentelemetry.io/otel/metric/instrument/syncfloat64" + "go.opentelemetry.io/otel/metric/unit" + sdkmetric "go.opentelemetry.io/otel/sdk/metric" + "go.opentelemetry.io/otel/sdk/metric/aggregation" + "go.opentelemetry.io/otel/sdk/metric/view" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/encoding/gzip" +) + +var ( + openTelemetryMeterProvider *sdkmetric.MeterProvider + openTelemetryGaugeCollector *gaugeCollector +) + +// RegisterOpenTelemetry registers all OpenTelemetry metrics. +func RegisterOpenTelemetry(ctx context.Context, config *types.OpenTelemetry) Registry { + if openTelemetryMeterProvider == nil { + var err error + if openTelemetryMeterProvider, err = newOpenTelemetryMeterProvider(ctx, config); err != nil { + log.Ctx(ctx).Err(err).Msg("Unable to create OpenTelemetry meter provider") + + return nil + } + } + + if openTelemetryGaugeCollector == nil { + openTelemetryGaugeCollector = newOpenTelemetryGaugeCollector() + } + + meter := global.Meter("github.com/traefik/traefik", + metric.WithInstrumentationVersion(version.Version)) + + reg := &standardRegistry{ + epEnabled: config.AddEntryPointsLabels, + routerEnabled: config.AddRoutersLabels, + svcEnabled: config.AddServicesLabels, + configReloadsCounter: newOTLPCounterFrom(meter, configReloadsTotalName, "Config reloads"), + configReloadsFailureCounter: newOTLPCounterFrom(meter, configReloadsFailuresTotalName, "Config reload failures"), + lastConfigReloadSuccessGauge: newOTLPGaugeFrom(meter, configLastReloadSuccessName, "Last config reload success", unit.Milliseconds), + lastConfigReloadFailureGauge: newOTLPGaugeFrom(meter, configLastReloadFailureName, "Last config reload failure", unit.Milliseconds), + tlsCertsNotAfterTimestampGauge: newOTLPGaugeFrom(meter, tlsCertsNotAfterTimestamp, "Certificate expiration timestamp", unit.Milliseconds), + } + + if config.AddEntryPointsLabels { + reg.entryPointReqsCounter = newOTLPCounterFrom(meter, entryPointReqsTotalName, + "How many HTTP requests processed on an entrypoint, partitioned by status code, protocol, and method.") + reg.entryPointReqsTLSCounter = newOTLPCounterFrom(meter, entryPointReqsTLSTotalName, + "How many HTTP requests with TLS processed on an entrypoint, partitioned by TLS Version and TLS cipher Used.") + reg.entryPointReqDurationHistogram, _ = NewHistogramWithScale(newOTLPHistogramFrom(meter, entryPointReqDurationName, + "How long it took to process the request on an entrypoint, partitioned by status code, protocol, and method.", + unit.Milliseconds), time.Second) + reg.entryPointOpenConnsGauge = newOTLPGaugeFrom(meter, entryPointOpenConnsName, + "How many open connections exist on an entrypoint, partitioned by method and protocol.", + unit.Dimensionless) + } + + if config.AddRoutersLabels { + reg.routerReqsCounter = newOTLPCounterFrom(meter, routerReqsTotalName, + "How many HTTP requests are processed on a router, partitioned by service, status code, protocol, and method.") + reg.routerReqsTLSCounter = newOTLPCounterFrom(meter, routerReqsTLSTotalName, + "How many HTTP requests with TLS are processed on a router, partitioned by service, TLS Version, and TLS cipher Used.") + reg.routerReqDurationHistogram, _ = NewHistogramWithScale(newOTLPHistogramFrom(meter, routerReqDurationName, + "How long it took to process the request on a router, partitioned by service, status code, protocol, and method.", + unit.Milliseconds), time.Second) + reg.routerOpenConnsGauge = newOTLPGaugeFrom(meter, routerOpenConnsName, + "How many open connections exist on a router, partitioned by service, method, and protocol.", + unit.Dimensionless) + } + + if config.AddServicesLabels { + reg.serviceReqsCounter = newOTLPCounterFrom(meter, serviceReqsTotalName, + "How many HTTP requests processed on a service, partitioned by status code, protocol, and method.") + reg.serviceReqsTLSCounter = newOTLPCounterFrom(meter, serviceReqsTLSTotalName, + "How many HTTP requests with TLS processed on a service, partitioned by TLS version and TLS cipher.") + reg.serviceReqDurationHistogram, _ = NewHistogramWithScale(newOTLPHistogramFrom(meter, serviceReqDurationName, + "How long it took to process the request on a service, partitioned by status code, protocol, and method.", + unit.Milliseconds), time.Second) + reg.serviceOpenConnsGauge = newOTLPGaugeFrom(meter, serviceOpenConnsName, + "How many open connections exist on a service, partitioned by method and protocol.", + unit.Dimensionless) + reg.serviceRetriesCounter = newOTLPCounterFrom(meter, serviceRetriesTotalName, + "How many request retries happened on a service.") + reg.serviceServerUpGauge = newOTLPGaugeFrom(meter, serviceServerUpName, + "service server is up, described by gauge value of 0 or 1.", + unit.Dimensionless) + } + + return reg +} + +// StopOpenTelemetry stops and resets Open-Telemetry client. +func StopOpenTelemetry() { + if openTelemetryMeterProvider == nil { + return + } + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + if err := openTelemetryMeterProvider.Shutdown(ctx); err != nil { + log.Err(err).Msg("Unable to shutdown OpenTelemetry meter provider") + } + + openTelemetryMeterProvider = nil +} + +// newOpenTelemetryMeterProvider creates a new controller.Controller. +func newOpenTelemetryMeterProvider(ctx context.Context, config *types.OpenTelemetry) (*sdkmetric.MeterProvider, error) { + var ( + exporter sdkmetric.Exporter + err error + ) + if config.GRPC != nil { + exporter, err = newGRPCExporter(ctx, config) + } else { + exporter, err = newHTTPExporter(ctx, config) + } + if err != nil { + return nil, fmt.Errorf("creating exporter: %w", err) + } + + opts := []sdkmetric.PeriodicReaderOption{ + sdkmetric.WithInterval(time.Duration(config.PushInterval)), + } + + // View to customize histogram buckets and rename a single histogram instrument. + customBucketsView, err := view.New( + // Match* to match instruments + view.MatchInstrumentName("traefik_*_request_duration_seconds"), + + view.WithSetAggregation(aggregation.ExplicitBucketHistogram{ + Boundaries: config.ExplicitBoundaries, + }), + ) + if err != nil { + return nil, fmt.Errorf("creating histogram view: %w", err) + } + + meterProvider := sdkmetric.NewMeterProvider(sdkmetric.WithReader( + sdkmetric.NewPeriodicReader(exporter, opts...), + customBucketsView, + )) + + global.SetMeterProvider(meterProvider) + + return meterProvider, nil +} + +func newHTTPExporter(ctx context.Context, config *types.OpenTelemetry) (sdkmetric.Exporter, error) { + host, port, err := net.SplitHostPort(config.Address) + if err != nil { + return nil, fmt.Errorf("invalid collector address %q: %w", config.Address, err) + } + + opts := []otlpmetrichttp.Option{ + otlpmetrichttp.WithEndpoint(fmt.Sprintf("%s:%s", host, port)), + otlpmetrichttp.WithHeaders(config.Headers), + otlpmetrichttp.WithCompression(otlpmetrichttp.GzipCompression), + } + + if config.Insecure { + opts = append(opts, otlpmetrichttp.WithInsecure()) + } + + if config.Path != "" { + opts = append(opts, otlpmetrichttp.WithURLPath(config.Path)) + } + + if config.TLS != nil { + tlsConfig, err := config.TLS.CreateTLSConfig(ctx) + if err != nil { + return nil, fmt.Errorf("creating TLS client config: %w", err) + } + + opts = append(opts, otlpmetrichttp.WithTLSClientConfig(tlsConfig)) + } + + return otlpmetrichttp.New(ctx, opts...) +} + +func newGRPCExporter(ctx context.Context, config *types.OpenTelemetry) (sdkmetric.Exporter, error) { + host, port, err := net.SplitHostPort(config.Address) + if err != nil { + return nil, fmt.Errorf("invalid collector address %q: %w", config.Address, err) + } + + opts := []otlpmetricgrpc.Option{ + otlpmetricgrpc.WithEndpoint(fmt.Sprintf("%s:%s", host, port)), + otlpmetricgrpc.WithHeaders(config.Headers), + otlpmetricgrpc.WithCompressor(gzip.Name), + } + + if config.Insecure { + opts = append(opts, otlpmetricgrpc.WithInsecure()) + } + + if config.TLS != nil { + tlsConfig, err := config.TLS.CreateTLSConfig(ctx) + if err != nil { + return nil, fmt.Errorf("creating TLS client config: %w", err) + } + + opts = append(opts, otlpmetricgrpc.WithTLSCredentials(credentials.NewTLS(tlsConfig))) + } + + return otlpmetricgrpc.New(ctx, opts...) +} + +func newOTLPCounterFrom(meter metric.Meter, name, desc string) *otelCounter { + c, _ := meter.SyncFloat64().Counter(name, + instrument.WithDescription(desc), + instrument.WithUnit(unit.Dimensionless), + ) + + return &otelCounter{ + ip: c, + } +} + +type otelCounter struct { + labelNamesValues otelLabelNamesValues + ip syncfloat64.Counter +} + +func (c *otelCounter) With(labelValues ...string) metrics.Counter { + return &otelCounter{ + labelNamesValues: c.labelNamesValues.With(labelValues...), + ip: c.ip, + } +} + +func (c *otelCounter) Add(delta float64) { + c.ip.Add(context.Background(), delta, c.labelNamesValues.ToLabels()...) +} + +type gaugeValue struct { + attributes otelLabelNamesValues + value float64 +} + +type gaugeCollector struct { + mu sync.Mutex + values map[string]map[string]gaugeValue +} + +func newOpenTelemetryGaugeCollector() *gaugeCollector { + return &gaugeCollector{ + values: make(map[string]map[string]gaugeValue), + } +} + +func (c *gaugeCollector) add(name string, delta float64, attributes otelLabelNamesValues) { + c.mu.Lock() + defer c.mu.Unlock() + + str := strings.Join(attributes, "") + + if _, exists := c.values[name]; !exists { + c.values[name] = map[string]gaugeValue{ + str: { + attributes: attributes, + value: delta, + }, + } + return + } + + v, exists := c.values[name][str] + if !exists { + c.values[name][str] = gaugeValue{ + attributes: attributes, + value: delta, + } + return + } + + c.values[name][str] = gaugeValue{ + attributes: attributes, + value: v.value + delta, + } +} + +func (c *gaugeCollector) set(name string, value float64, attributes otelLabelNamesValues) { + c.mu.Lock() + defer c.mu.Unlock() + + if _, exists := c.values[name]; !exists { + c.values[name] = make(map[string]gaugeValue) + } + + c.values[name][strings.Join(attributes, "")] = gaugeValue{ + attributes: attributes, + value: value, + } +} + +func newOTLPGaugeFrom(meter metric.Meter, name, desc string, u unit.Unit) *otelGauge { + openTelemetryGaugeCollector.values[name] = make(map[string]gaugeValue) + + c, _ := meter.AsyncFloat64().Gauge(name, + instrument.WithDescription(desc), + instrument.WithUnit(u), + ) + + err := meter.RegisterCallback([]instrument.Asynchronous{c}, func(ctx context.Context) { + openTelemetryGaugeCollector.mu.Lock() + defer openTelemetryGaugeCollector.mu.Unlock() + + values, exists := openTelemetryGaugeCollector.values[name] + if !exists { + return + } + + for _, value := range values { + c.Observe(ctx, value.value, value.attributes.ToLabels()...) + } + }) + if err != nil { + log.Err(err).Msg("Unable to register OpenTelemetry meter callback") + } + + return &otelGauge{ + ip: c, + name: name, + } +} + +type otelGauge struct { + labelNamesValues otelLabelNamesValues + ip asyncfloat64.Gauge + name string +} + +func (g *otelGauge) With(labelValues ...string) metrics.Gauge { + return &otelGauge{ + labelNamesValues: g.labelNamesValues.With(labelValues...), + ip: g.ip, + name: g.name, + } +} + +func (g *otelGauge) Add(delta float64) { + openTelemetryGaugeCollector.add(g.name, delta, g.labelNamesValues) +} + +func (g *otelGauge) Set(value float64) { + openTelemetryGaugeCollector.set(g.name, value, g.labelNamesValues) +} + +func newOTLPHistogramFrom(meter metric.Meter, name, desc string, u unit.Unit) *otelHistogram { + c, _ := meter.SyncFloat64().Histogram(name, + instrument.WithDescription(desc), + instrument.WithUnit(u), + ) + + return &otelHistogram{ + ip: c, + } +} + +type otelHistogram struct { + labelNamesValues otelLabelNamesValues + ip syncfloat64.Histogram +} + +func (h *otelHistogram) With(labelValues ...string) metrics.Histogram { + return &otelHistogram{ + labelNamesValues: h.labelNamesValues.With(labelValues...), + ip: h.ip, + } +} + +func (h *otelHistogram) Observe(incr float64) { + h.ip.Record(context.Background(), incr, h.labelNamesValues.ToLabels()...) +} + +// otelLabelNamesValues is the equivalent of prometheus' labelNamesValues +// but adapted to OpenTelemetry. +// otelLabelNamesValues is a type alias that provides validation on its With +// method. +// Metrics may include it as a member to help them satisfy With semantics and +// save some code duplication. +type otelLabelNamesValues []string + +// With validates the input, and returns a new aggregate otelLabelNamesValues. +func (lvs otelLabelNamesValues) With(labelValues ...string) otelLabelNamesValues { + if len(labelValues)%2 != 0 { + labelValues = append(labelValues, "unknown") + } + return append(lvs, labelValues...) +} + +// ToLabels is a convenience method to convert a otelLabelNamesValues +// to the native attribute.KeyValue. +func (lvs otelLabelNamesValues) ToLabels() []attribute.KeyValue { + labels := make([]attribute.KeyValue, len(lvs)/2) + for i := 0; i < len(labels); i++ { + labels[i] = attribute.String(lvs[2*i], lvs[2*i+1]) + } + return labels +} diff --git a/pkg/metrics/opentelemetry_test.go b/pkg/metrics/opentelemetry_test.go new file mode 100644 index 000000000..16890b6ba --- /dev/null +++ b/pkg/metrics/opentelemetry_test.go @@ -0,0 +1,446 @@ +package metrics + +import ( + "compress/gzip" + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "net/http/httptest" + "net/url" + "strconv" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + ptypes "github.com/traefik/paerser/types" + "github.com/traefik/traefik/v2/pkg/types" + "go.opentelemetry.io/collector/pdata/pmetric/pmetricotlp" + "go.opentelemetry.io/otel/attribute" +) + +func TestOpenTelemetry_labels(t *testing.T) { + tests := []struct { + desc string + values otelLabelNamesValues + with []string + expect []attribute.KeyValue + }{ + { + desc: "with no starting value", + values: otelLabelNamesValues{}, + expect: []attribute.KeyValue{}, + }, + { + desc: "with one starting value", + values: otelLabelNamesValues{"foo"}, + expect: []attribute.KeyValue{}, + }, + { + desc: "with two starting value", + values: otelLabelNamesValues{"foo", "bar"}, + expect: []attribute.KeyValue{attribute.String("foo", "bar")}, + }, + { + desc: "with no starting value, and with one other value", + values: otelLabelNamesValues{}, + with: []string{"baz"}, + expect: []attribute.KeyValue{attribute.String("baz", "unknown")}, + }, + { + desc: "with no starting value, and with two other value", + values: otelLabelNamesValues{}, + with: []string{"baz", "buz"}, + expect: []attribute.KeyValue{attribute.String("baz", "buz")}, + }, + { + desc: "with one starting value, and with one other value", + values: otelLabelNamesValues{"foo"}, + with: []string{"baz"}, + expect: []attribute.KeyValue{attribute.String("foo", "baz")}, + }, + { + desc: "with one starting value, and with two other value", + values: otelLabelNamesValues{"foo"}, + with: []string{"baz", "buz"}, + expect: []attribute.KeyValue{attribute.String("foo", "baz")}, + }, + { + desc: "with two starting value, and with one other value", + values: otelLabelNamesValues{"foo", "bar"}, + with: []string{"baz"}, + expect: []attribute.KeyValue{ + attribute.String("foo", "bar"), + attribute.String("baz", "unknown"), + }, + }, + { + desc: "with two starting value, and with two other value", + values: otelLabelNamesValues{"foo", "bar"}, + with: []string{"baz", "buz"}, + expect: []attribute.KeyValue{ + attribute.String("foo", "bar"), + attribute.String("baz", "buz"), + }, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.desc, func(t *testing.T) { + t.Parallel() + + assert.Equal(t, test.expect, test.values.With(test.with...).ToLabels()) + }) + } +} + +func TestOpenTelemetry_GaugeCollectorAdd(t *testing.T) { + tests := []struct { + desc string + gc *gaugeCollector + delta float64 + name string + attributes otelLabelNamesValues + expect map[string]map[string]gaugeValue + }{ + { + desc: "empty collector", + gc: newOpenTelemetryGaugeCollector(), + delta: 1, + name: "foo", + expect: map[string]map[string]gaugeValue{ + "foo": {"": {value: 1}}, + }, + }, + { + desc: "initialized collector", + gc: &gaugeCollector{ + values: map[string]map[string]gaugeValue{ + "foo": {"": {value: 1}}, + }, + }, + delta: 1, + name: "foo", + expect: map[string]map[string]gaugeValue{ + "foo": {"": {value: 2}}, + }, + }, + { + desc: "initialized collector, values with label (only the last one counts)", + gc: &gaugeCollector{ + values: map[string]map[string]gaugeValue{ + "foo": { + "bar": { + attributes: otelLabelNamesValues{"bar"}, + value: 1, + }, + }, + }, + }, + delta: 1, + name: "foo", + expect: map[string]map[string]gaugeValue{ + "foo": { + "": { + value: 1, + }, + "bar": { + attributes: otelLabelNamesValues{"bar"}, + value: 1, + }, + }, + }, + }, + { + desc: "initialized collector, values with label on set", + gc: &gaugeCollector{ + values: map[string]map[string]gaugeValue{ + "foo": {"bar": {value: 1}}, + }, + }, + delta: 1, + name: "foo", + attributes: otelLabelNamesValues{"baz"}, + expect: map[string]map[string]gaugeValue{ + "foo": { + "bar": { + value: 1, + }, + "baz": { + value: 1, + attributes: otelLabelNamesValues{"baz"}, + }, + }, + }, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.desc, func(t *testing.T) { + t.Parallel() + + test.gc.add(test.name, test.delta, test.attributes) + + assert.Equal(t, test.expect, test.gc.values) + }) + } +} + +func TestOpenTelemetry_GaugeCollectorSet(t *testing.T) { + tests := []struct { + desc string + gc *gaugeCollector + value float64 + name string + attributes otelLabelNamesValues + expect map[string]map[string]gaugeValue + }{ + { + desc: "empty collector", + gc: newOpenTelemetryGaugeCollector(), + value: 1, + name: "foo", + expect: map[string]map[string]gaugeValue{ + "foo": {"": {value: 1}}, + }, + }, + { + desc: "initialized collector", + gc: &gaugeCollector{ + values: map[string]map[string]gaugeValue{ + "foo": {"": {value: 1}}, + }, + }, + value: 1, + name: "foo", + expect: map[string]map[string]gaugeValue{ + "foo": {"": {value: 1}}, + }, + }, + { + desc: "initialized collector, values with label", + gc: &gaugeCollector{ + values: map[string]map[string]gaugeValue{ + "foo": { + "bar": { + attributes: otelLabelNamesValues{"bar"}, + value: 1, + }, + }, + }, + }, + value: 1, + name: "foo", + expect: map[string]map[string]gaugeValue{ + "foo": { + "": { + value: 1, + }, + "bar": { + attributes: otelLabelNamesValues{"bar"}, + value: 1, + }, + }, + }, + }, + { + desc: "initialized collector, values with label on set", + gc: &gaugeCollector{ + values: map[string]map[string]gaugeValue{ + "foo": {"": {value: 1}}, + }, + }, + value: 1, + name: "foo", + attributes: otelLabelNamesValues{"bar"}, + expect: map[string]map[string]gaugeValue{ + "foo": { + "": { + value: 1, + }, + "bar": { + value: 1, + attributes: otelLabelNamesValues{"bar"}, + }, + }, + }, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.desc, func(t *testing.T) { + t.Parallel() + + test.gc.set(test.name, test.value, test.attributes) + + assert.Equal(t, test.expect, test.gc.values) + }) + } +} + +func TestOpenTelemetry(t *testing.T) { + t.Parallel() + + c := make(chan *string) + defer close(c) + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + gzr, err := gzip.NewReader(r.Body) + require.NoError(t, err) + + body, err := io.ReadAll(gzr) + require.NoError(t, err) + + req := pmetricotlp.NewExportRequest() + err = req.UnmarshalProto(body) + require.NoError(t, err) + + marshalledReq, err := json.Marshal(req) + require.NoError(t, err) + + bodyStr := string(marshalledReq) + c <- &bodyStr + + _, err = fmt.Fprintln(w, "ok") + require.NoError(t, err) + })) + defer ts.Close() + + sURL, err := url.Parse(ts.URL) + require.NoError(t, err) + + var cfg types.OpenTelemetry + (&cfg).SetDefaults() + cfg.AddRoutersLabels = true + cfg.Address = sURL.Host + cfg.Insecure = true + cfg.PushInterval = ptypes.Duration(10 * time.Millisecond) + + registry := RegisterOpenTelemetry(context.Background(), &cfg) + require.NotNil(t, registry) + + if !registry.IsEpEnabled() || !registry.IsRouterEnabled() || !registry.IsSvcEnabled() { + t.Fatalf("registry should return true for IsEnabled(), IsRouterEnabled() and IsSvcEnabled()") + } + + // TODO: the len of startUnixNano is no supposed to be 20, it should be 19 + expectedServer := []string{ + `({"name":"traefik_config_reloads_total","description":"Config reloads","unit":"1","sum":{"dataPoints":\[{"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1}\],"aggregationTemporality":2,"isMonotonic":true}})`, + `({"name":"traefik_config_reloads_failure_total","description":"Config reload failures","unit":"1","sum":{"dataPoints":\[{"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1}\],"aggregationTemporality":2,"isMonotonic":true}})`, + `({"name":"traefik_config_last_reload_success","description":"Last config reload success","unit":"ms","gauge":{"dataPoints":\[{"startTimeUnixNano":"[\d]{20}","timeUnixNano":"[\d]{19}","asDouble":1}\]}})`, + `({"name":"traefik_config_last_reload_failure","description":"Last config reload failure","unit":"ms","gauge":{"dataPoints":\[{"startTimeUnixNano":"[\d]{20}","timeUnixNano":"[\d]{19}","asDouble":1}\]}})`, + } + + registry.ConfigReloadsCounter().Add(1) + registry.ConfigReloadsFailureCounter().Add(1) + registry.LastConfigReloadSuccessGauge().Set(1) + registry.LastConfigReloadFailureGauge().Set(1) + msgServer := <-c + + assertMessage(t, *msgServer, expectedServer) + + expectedTLS := []string{ + `({"name":"traefik_tls_certs_not_after","description":"Certificate expiration timestamp","unit":"ms","gauge":{"dataPoints":\[{"attributes":\[{"key":"key","value":{"stringValue":"value"}}\],"startTimeUnixNano":"[\d]{20}","timeUnixNano":"[\d]{19}","asDouble":1}\]}})`, + } + + registry.TLSCertsNotAfterTimestampGauge().With("key", "value").Set(1) + msgTLS := <-c + + assertMessage(t, *msgTLS, expectedTLS) + + expectedEntrypoint := []string{ + `({"name":"traefik_entrypoint_requests_total","description":"How many HTTP requests processed on an entrypoint, partitioned by status code, protocol, and method.","unit":"1","sum":{"dataPoints":\[{"attributes":\[{"key":"code","value":{"stringValue":"200"}},{"key":"entrypoint","value":{"stringValue":"test1"}},{"key":"method","value":{"stringValue":"GET"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1}\],"aggregationTemporality":2,"isMonotonic":true}})`, + `({"name":"traefik_entrypoint_requests_tls_total","description":"How many HTTP requests with TLS processed on an entrypoint, partitioned by TLS Version and TLS cipher Used.","unit":"1","sum":{"dataPoints":\[{"attributes":\[{"key":"entrypoint","value":{"stringValue":"test2"}},{"key":"tls_cipher","value":{"stringValue":"bar"}},{"key":"tls_version","value":{"stringValue":"foo"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1}\],"aggregationTemporality":2,"isMonotonic":true}})`, + `({"name":"traefik_entrypoint_request_duration_seconds","description":"How long it took to process the request on an entrypoint, partitioned by status code, protocol, and method.","unit":"ms","histogram":{"dataPoints":\[{"attributes":\[{"key":"entrypoint","value":{"stringValue":"test3"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","count":"1","sum":10000,"bucketCounts":\["0","0","0","0","0","0","0","0","0","0","0","1"\],"explicitBounds":\[0.005,0.01,0.025,0.05,0.1,0.25,0.5,1,2.5,5,10\],"min":10000,"max":10000}\],"aggregationTemporality":2}})`, + `({"name":"traefik_entrypoint_open_connections","description":"How many open connections exist on an entrypoint, partitioned by method and protocol.","unit":"1","gauge":{"dataPoints":\[{"attributes":\[{"key":"entrypoint","value":{"stringValue":"test4"}}\],"startTimeUnixNano":"[\d]{20}","timeUnixNano":"[\d]{19}","asDouble":1}\]}})`, + } + + registry.EntryPointReqsCounter().With("entrypoint", "test1", "code", strconv.Itoa(http.StatusOK), "method", http.MethodGet).Add(1) + registry.EntryPointReqsTLSCounter().With("entrypoint", "test2", "tls_version", "foo", "tls_cipher", "bar").Add(1) + registry.EntryPointReqDurationHistogram().With("entrypoint", "test3").Observe(10000) + registry.EntryPointOpenConnsGauge().With("entrypoint", "test4").Set(1) + msgEntrypoint := <-c + + assertMessage(t, *msgEntrypoint, expectedEntrypoint) + + expectedRouter := []string{ + `({"name":"traefik_router_requests_total","description":"How many HTTP requests are processed on a router, partitioned by service, status code, protocol, and method.","unit":"1","sum":{"dataPoints":\[{"attributes":\[{"key":"code","value":{"stringValue":"(?:200|404)"}},{"key":"method","value":{"stringValue":"GET"}},{"key":"router","value":{"stringValue":"RouterReqsCounter"}},{"key":"service","value":{"stringValue":"test"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1},{"attributes":\[{"key":"code","value":{"stringValue":"(?:200|404)"}},{"key":"method","value":{"stringValue":"GET"}},{"key":"router","value":{"stringValue":"RouterReqsCounter"}},{"key":"service","value":{"stringValue":"test"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1}\],"aggregationTemporality":2,"isMonotonic":true}})`, + `({"name":"traefik_router_requests_tls_total","description":"How many HTTP requests with TLS are processed on a router, partitioned by service, TLS Version, and TLS cipher Used.","unit":"1","sum":{"dataPoints":\[{"attributes":\[{"key":"router","value":{"stringValue":"demo"}},{"key":"service","value":{"stringValue":"test"}},{"key":"tls_cipher","value":{"stringValue":"bar"}},{"key":"tls_version","value":{"stringValue":"foo"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1}\],"aggregationTemporality":2,"isMonotonic":true}})`, + `({"name":"traefik_router_request_duration_seconds","description":"How long it took to process the request on a router, partitioned by service, status code, protocol, and method.","unit":"ms","histogram":{"dataPoints":\[{"attributes":\[{"key":"code","value":{"stringValue":"200"}},{"key":"router","value":{"stringValue":"demo"}},{"key":"service","value":{"stringValue":"test"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","count":"1","sum":10000,"bucketCounts":\["0","0","0","0","0","0","0","0","0","0","0","1"\],"explicitBounds":\[0.005,0.01,0.025,0.05,0.1,0.25,0.5,1,2.5,5,10\],"min":10000,"max":10000}\],"aggregationTemporality":2}})`, + `({"name":"traefik_router_open_connections","description":"How many open connections exist on a router, partitioned by service, method, and protocol.","unit":"1","gauge":{"dataPoints":\[{"attributes":\[{"key":"router","value":{"stringValue":"demo"}},{"key":"service","value":{"stringValue":"test"}}\],"startTimeUnixNano":"[\d]{20}","timeUnixNano":"[\d]{19}","asDouble":1}\]}})`, + } + + registry.RouterReqsCounter().With("router", "RouterReqsCounter", "service", "test", "code", strconv.Itoa(http.StatusNotFound), "method", http.MethodGet).Add(1) + registry.RouterReqsCounter().With("router", "RouterReqsCounter", "service", "test", "code", strconv.Itoa(http.StatusOK), "method", http.MethodGet).Add(1) + registry.RouterReqsTLSCounter().With("router", "demo", "service", "test", "tls_version", "foo", "tls_cipher", "bar").Add(1) + registry.RouterReqDurationHistogram().With("router", "demo", "service", "test", "code", strconv.Itoa(http.StatusOK)).Observe(10000) + registry.RouterOpenConnsGauge().With("router", "demo", "service", "test").Set(1) + msgRouter := <-c + + assertMessage(t, *msgRouter, expectedRouter) + + expectedService := []string{ + `({"name":"traefik_service_requests_total","description":"How many HTTP requests processed on a service, partitioned by status code, protocol, and method.","unit":"1","sum":{"dataPoints":\[{"attributes":\[{"key":"code","value":{"stringValue":"(?:200|404)"}},{"key":"method","value":{"stringValue":"GET"}},{"key":"service","value":{"stringValue":"ServiceReqsCounter"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1},{"attributes":\[{"key":"code","value":{"stringValue":"(?:200|404)"}},{"key":"method","value":{"stringValue":"GET"}},{"key":"service","value":{"stringValue":"ServiceReqsCounter"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1}\],"aggregationTemporality":2,"isMonotonic":true}})`, + `({"name":"traefik_service_requests_tls_total","description":"How many HTTP requests with TLS processed on a service, partitioned by TLS version and TLS cipher.","unit":"1","sum":{"dataPoints":\[{"attributes":\[{"key":"service","value":{"stringValue":"test"}},{"key":"tls_cipher","value":{"stringValue":"bar"}},{"key":"tls_version","value":{"stringValue":"foo"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1}\],"aggregationTemporality":2,"isMonotonic":true}})`, + `({"name":"traefik_service_request_duration_seconds","description":"How long it took to process the request on a service, partitioned by status code, protocol, and method.","unit":"ms","histogram":{"dataPoints":\[{"attributes":\[{"key":"code","value":{"stringValue":"200"}},{"key":"service","value":{"stringValue":"test"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","count":"1","sum":10000,"bucketCounts":\["0","0","0","0","0","0","0","0","0","0","0","1"\],"explicitBounds":\[0.005,0.01,0.025,0.05,0.1,0.25,0.5,1,2.5,5,10\],"min":10000,"max":10000}\],"aggregationTemporality":2}})`, + `({"name":"traefik_service_server_up","description":"service server is up, described by gauge value of 0 or 1.","unit":"1","gauge":{"dataPoints":\[{"attributes":\[{"key":"service","value":{"stringValue":"test"}},{"key":"url","value":{"stringValue":"http://127.0.0.1"}}\],"startTimeUnixNano":"[\d]{20}","timeUnixNano":"[\d]{19}","asDouble":1}\]}})`, + } + + registry.ServiceReqsCounter().With("service", "ServiceReqsCounter", "code", strconv.Itoa(http.StatusOK), "method", http.MethodGet).Add(1) + registry.ServiceReqsCounter().With("service", "ServiceReqsCounter", "code", strconv.Itoa(http.StatusNotFound), "method", http.MethodGet).Add(1) + registry.ServiceReqsTLSCounter().With("service", "test", "tls_version", "foo", "tls_cipher", "bar").Add(1) + registry.ServiceReqDurationHistogram().With("service", "test", "code", strconv.Itoa(http.StatusOK)).Observe(10000) + registry.ServiceServerUpGauge().With("service", "test", "url", "http://127.0.0.1").Set(1) + msgService := <-c + + assertMessage(t, *msgService, expectedService) + + expectedServiceRetries := []string{ + `({"attributes":\[{"key":"service","value":{"stringValue":"foobar"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":1})`, + `({"attributes":\[{"key":"service","value":{"stringValue":"test"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","asDouble":2})`, + } + + registry.ServiceRetriesCounter().With("service", "test").Add(1) + registry.ServiceRetriesCounter().With("service", "test").Add(1) + registry.ServiceRetriesCounter().With("service", "foobar").Add(1) + msgServiceRetries := <-c + + assertMessage(t, *msgServiceRetries, expectedServiceRetries) + + expectedServiceOpenConns := []string{ + `({"attributes":\[{"key":"service","value":{"stringValue":"test"}}\],"startTimeUnixNano":"[\d]{20}","timeUnixNano":"[\d]{19}","asDouble":3})`, + `({"attributes":\[{"key":"service","value":{"stringValue":"foobar"}}\],"startTimeUnixNano":"[\d]{20}","timeUnixNano":"[\d]{19}","asDouble":1})`, + } + + registry.ServiceOpenConnsGauge().With("service", "test").Set(1) + registry.ServiceOpenConnsGauge().With("service", "test").Add(1) + registry.ServiceOpenConnsGauge().With("service", "test").Add(1) + registry.ServiceOpenConnsGauge().With("service", "foobar").Add(1) + msgServiceOpenConns := <-c + + assertMessage(t, *msgServiceOpenConns, expectedServiceOpenConns) + + expectedEntryPointReqDuration := []string{ + `({"attributes":\[{"key":"entrypoint","value":{"stringValue":"myEntrypoint"}}\],"startTimeUnixNano":"[\d]{19}","timeUnixNano":"[\d]{19}","count":"2","sum":30000,"bucketCounts":\["0","0","0","0","0","0","0","0","0","0","0","2"\],"explicitBounds":\[0.005,0.01,0.025,0.05,0.1,0.25,0.5,1,2.5,5,10\],"min":10000,"max":20000})`, + } + + registry.EntryPointReqDurationHistogram().With("entrypoint", "myEntrypoint").Observe(10000) + registry.EntryPointReqDurationHistogram().With("entrypoint", "myEntrypoint").Observe(20000) + msgEntryPointReqDurationHistogram := <-c + + assertMessage(t, *msgEntryPointReqDurationHistogram, expectedEntryPointReqDuration) + + // We need to unlock the HTTP Server for the last export call when stopping + // OpenTelemetry. + go func() { + <-c + }() + StopOpenTelemetry() +} diff --git a/pkg/server/server.go b/pkg/server/server.go index edd0cdb02..421437a38 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -113,4 +113,5 @@ func stopMetricsClients() { metrics.StopStatsd() metrics.StopInfluxDB() metrics.StopInfluxDB2() + metrics.StopOpenTelemetry() } diff --git a/pkg/tracing/opentelemetry/opentelemetry.go b/pkg/tracing/opentelemetry/opentelemetry.go new file mode 100644 index 000000000..d42770ae3 --- /dev/null +++ b/pkg/tracing/opentelemetry/opentelemetry.go @@ -0,0 +1,138 @@ +package opentelemetry + +import ( + "context" + "fmt" + "io" + "net" + + "github.com/opentracing/opentracing-go" + "github.com/rs/zerolog/log" + "github.com/traefik/traefik/v2/pkg/types" + "github.com/traefik/traefik/v2/pkg/version" + "go.opentelemetry.io/otel" + oteltracer "go.opentelemetry.io/otel/bridge/opentracing" + "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" + sdktrace "go.opentelemetry.io/otel/sdk/trace" + "go.opentelemetry.io/otel/trace" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/encoding/gzip" +) + +// Config provides configuration settings for the open-telemetry tracer. +type Config struct { + // 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" export:"true" label:"allowEmpty" file:"allowEmpty"` + + 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"` +} + +// SetDefaults sets the default values. +func (c *Config) SetDefaults() { + c.Address = "localhost:4318" +} + +// Setup sets up the tracer. +func (c *Config) Setup(componentName string) (opentracing.Tracer, io.Closer, error) { + var ( + err error + exporter *otlptrace.Exporter + ) + if c.GRPC != nil { + exporter, err = c.setupGRPCExporter() + } else { + exporter, err = c.setupHTTPExporter() + } + if err != nil { + return nil, nil, fmt.Errorf("setting up exporter: %w", err) + } + + bt := oteltracer.NewBridgeTracer() + bt.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{})) + + bt.SetOpenTelemetryTracer(otel.Tracer(componentName, trace.WithInstrumentationVersion(version.Version))) + opentracing.SetGlobalTracer(bt) + + tracerProvider := sdktrace.NewTracerProvider(sdktrace.WithBatcher(exporter)) + otel.SetTracerProvider(tracerProvider) + + log.Debug().Msg("OpenTelemetry tracer configured") + + return bt, tpCloser{provider: tracerProvider}, err +} + +func (c *Config) setupHTTPExporter() (*otlptrace.Exporter, error) { + host, port, err := net.SplitHostPort(c.Address) + if err != nil { + return nil, fmt.Errorf("invalid collector address %q: %w", c.Address, err) + } + + opts := []otlptracehttp.Option{ + otlptracehttp.WithEndpoint(fmt.Sprintf("%s:%s", host, port)), + otlptracehttp.WithHeaders(c.Headers), + otlptracehttp.WithCompression(otlptracehttp.GzipCompression), + } + + if c.Insecure { + opts = append(opts, otlptracehttp.WithInsecure()) + } + + if c.Path != "" { + opts = append(opts, otlptracehttp.WithURLPath(c.Path)) + } + + if c.TLS != nil { + tlsConfig, err := c.TLS.CreateTLSConfig(context.Background()) + if err != nil { + return nil, fmt.Errorf("creating TLS client config: %w", err) + } + + opts = append(opts, otlptracehttp.WithTLSClientConfig(tlsConfig)) + } + + return otlptrace.New(context.Background(), otlptracehttp.NewClient(opts...)) +} + +func (c *Config) setupGRPCExporter() (*otlptrace.Exporter, error) { + host, port, err := net.SplitHostPort(c.Address) + if err != nil { + return nil, fmt.Errorf("invalid collector address %q: %w", c.Address, err) + } + + opts := []otlptracegrpc.Option{ + otlptracegrpc.WithEndpoint(fmt.Sprintf("%s:%s", host, port)), + otlptracegrpc.WithHeaders(c.Headers), + otlptracegrpc.WithCompressor(gzip.Name), + } + + if c.Insecure { + opts = append(opts, otlptracegrpc.WithInsecure()) + } + + if c.TLS != nil { + tlsConfig, err := c.TLS.CreateTLSConfig(context.Background()) + if err != nil { + return nil, fmt.Errorf("creating TLS client config: %w", err) + } + + opts = append(opts, otlptracegrpc.WithTLSCredentials(credentials.NewTLS(tlsConfig))) + } + + return otlptrace.New(context.Background(), otlptracegrpc.NewClient(opts...)) +} + +// tpCloser converts a TraceProvider into an io.Closer. +type tpCloser struct { + provider *sdktrace.TracerProvider +} + +func (t tpCloser) Close() error { + return t.provider.Shutdown(context.Background()) +} diff --git a/pkg/tracing/opentelemetry/opentelemetry_test.go b/pkg/tracing/opentelemetry/opentelemetry_test.go new file mode 100644 index 000000000..9d76f71d3 --- /dev/null +++ b/pkg/tracing/opentelemetry/opentelemetry_test.go @@ -0,0 +1,67 @@ +package opentelemetry + +import ( + "compress/gzip" + "context" + "encoding/json" + "io" + "net/http" + "net/http/httptest" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + mtracing "github.com/traefik/traefik/v2/pkg/middlewares/tracing" + "github.com/traefik/traefik/v2/pkg/tracing" + "go.opentelemetry.io/collector/pdata/ptrace/ptraceotlp" +) + +func TestTraceContextPropagation(t *testing.T) { + t.Parallel() + + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + gzr, err := gzip.NewReader(r.Body) + require.NoError(t, err) + + body, err := io.ReadAll(gzr) + require.NoError(t, err) + + req := ptraceotlp.NewExportRequest() + err = req.UnmarshalProto(body) + require.NoError(t, err) + + marshalledReq, err := json.Marshal(req) + require.NoError(t, err) + + bodyStr := string(marshalledReq) + assert.Regexp(t, `("traceId":"00000000000000000000000000000001")`, bodyStr) + assert.Regexp(t, `("parentSpanId":"0000000000000001")`, bodyStr) + assert.Regexp(t, `("traceState":"foo=bar")`, bodyStr) + })) + defer ts.Close() + + cfg := Config{ + Address: strings.TrimPrefix(ts.URL, "http://"), + Insecure: true, + } + + newTracing, err := tracing.NewTracing("", 0, &cfg) + require.NoError(t, err) + defer newTracing.Close() + + req := httptest.NewRequest(http.MethodGet, "http://www.test.com", nil) + req.Header.Set("traceparent", "00-00000000000000000000000000000001-0000000000000001-00") + req.Header.Set("tracestate", "foo=bar") + rw := httptest.NewRecorder() + + var forwarded bool + next := http.HandlerFunc(func(http.ResponseWriter, *http.Request) { + forwarded = true + }) + + handler := mtracing.NewEntryPoint(context.Background(), newTracing, "test", next) + handler.ServeHTTP(rw, req) + + require.True(t, forwarded) +} diff --git a/pkg/tracing/operation_name_test.go b/pkg/tracing/operation_name_test.go index dd9542c67..599151098 100644 --- a/pkg/tracing/operation_name_test.go +++ b/pkg/tracing/operation_name_test.go @@ -72,8 +72,8 @@ func TestComputeHash(t *testing.T) { }{ { desc: "hashing", - text: "some very long pice of text", - expected: "0258ea1c", + text: "some very long piece of text", + expected: "0c6e798b", }, { desc: "short text less than limit 10", @@ -109,7 +109,7 @@ func TestTruncateString(t *testing.T) { }, { desc: "basic truncate with limit 10", - text: "some very long pice of text", + text: "some very long piece of text", limit: 10, expected: "some ve...", }, diff --git a/pkg/types/metrics.go b/pkg/types/metrics.go index de3b85a06..ddcf71d96 100644 --- a/pkg/types/metrics.go +++ b/pkg/types/metrics.go @@ -10,11 +10,12 @@ import ( // Metrics provides options to expose and send Traefik metrics to different third party monitoring systems. type Metrics struct { - Prometheus *Prometheus `description:"Prometheus metrics exporter type." json:"prometheus,omitempty" toml:"prometheus,omitempty" yaml:"prometheus,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` - Datadog *Datadog `description:"Datadog metrics exporter type." json:"datadog,omitempty" toml:"datadog,omitempty" yaml:"datadog,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` - StatsD *Statsd `description:"StatsD metrics exporter type." json:"statsD,omitempty" toml:"statsD,omitempty" yaml:"statsD,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` - InfluxDB *InfluxDB `description:"InfluxDB metrics exporter type." json:"influxDB,omitempty" toml:"influxDB,omitempty" yaml:"influxDB,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` - InfluxDB2 *InfluxDB2 `description:"InfluxDB v2 metrics exporter type." json:"influxDB2,omitempty" toml:"influxDB2,omitempty" yaml:"influxDB2,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` + Prometheus *Prometheus `description:"Prometheus metrics exporter type." json:"prometheus,omitempty" toml:"prometheus,omitempty" yaml:"prometheus,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` + Datadog *Datadog `description:"Datadog metrics exporter type." json:"datadog,omitempty" toml:"datadog,omitempty" yaml:"datadog,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` + StatsD *Statsd `description:"StatsD metrics exporter type." json:"statsD,omitempty" toml:"statsD,omitempty" yaml:"statsD,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` + InfluxDB *InfluxDB `description:"InfluxDB metrics exporter type." json:"influxDB,omitempty" toml:"influxDB,omitempty" yaml:"influxDB,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` + InfluxDB2 *InfluxDB2 `description:"InfluxDB v2 metrics exporter type." json:"influxDB2,omitempty" toml:"influxDB2,omitempty" yaml:"influxDB2,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` + OpenTelemetry *OpenTelemetry `description:"OpenTelemetry metrics exporter type." json:"openTelemetry,omitempty" toml:"openTelemetry,omitempty" yaml:"openTelemetry,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` } // Prometheus can contain specific configuration used by the Prometheus Metrics exporter. @@ -127,6 +128,32 @@ func (i *InfluxDB2) SetDefaults() { i.AddServicesLabels = true } +// OpenTelemetry contains specific configuration used by the OpenTelemetry Metrics exporter. +type OpenTelemetry 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" export:"true" label:"allowEmpty" file:"allowEmpty"` + + Address string `description:"Address (host:port) of the collector endpoint." json:"address,omitempty" toml:"address,omitempty" yaml:"address,omitempty"` + AddEntryPointsLabels bool `description:"Enable metrics on entry points." json:"addEntryPointsLabels,omitempty" toml:"addEntryPointsLabels,omitempty" yaml:"addEntryPointsLabels,omitempty" export:"true"` + AddRoutersLabels bool `description:"Enable metrics on routers." json:"addRoutersLabels,omitempty" toml:"addRoutersLabels,omitempty" yaml:"addRoutersLabels,omitempty" export:"true"` + AddServicesLabels bool `description:"Enable metrics on services." json:"addServicesLabels,omitempty" toml:"addServicesLabels,omitempty" yaml:"addServicesLabels,omitempty" export:"true"` + ExplicitBoundaries []float64 `description:"Boundaries for latency metrics." json:"explicitBoundaries,omitempty" toml:"explicitBoundaries,omitempty" yaml:"explicitBoundaries,omitempty" export:"true"` + Headers map[string]string `description:"Headers sent with payload." json:"headers,omitempty" toml:"headers,omitempty" yaml:"headers,omitempty" export:"true"` + Insecure bool `description:"Disables client transport security for the exporter." json:"insecure,omitempty" toml:"insecure,omitempty" yaml:"insecure,omitempty" export:"true"` + Path string `description:"Set the URL path of the collector endpoint." json:"path,omitempty" toml:"path,omitempty" yaml:"path,omitempty" export:"true"` + PushInterval types.Duration `description:"Period between calls to collect a checkpoint." json:"pushInterval,omitempty" toml:"pushInterval,omitempty" yaml:"pushInterval,omitempty" export:"true"` + TLS *ClientTLS `description:"Enable TLS support." json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" export:"true"` +} + +// SetDefaults sets the default values. +func (o *OpenTelemetry) SetDefaults() { + o.Address = "localhost:4318" + o.AddEntryPointsLabels = true + o.AddServicesLabels = true + o.ExplicitBoundaries = []float64{.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10} + o.PushInterval = types.Duration(10 * time.Second) +} + // Statistics provides options for monitoring request and response stats. type Statistics struct { RecentErrors int `description:"Number of recent errors logged." json:"recentErrors,omitempty" toml:"recentErrors,omitempty" yaml:"recentErrors,omitempty" export:"true"`