From 8dcc74b15932c3396ca5f8e5228c02a7956ca03c Mon Sep 17 00:00:00 2001 From: Shawn Poulson <92753637+Baliedge@users.noreply.github.com> Date: Mon, 1 Aug 2022 17:17:17 -0400 Subject: [PATCH] Refactor tracing using holster OpenTelemetry tooling. (#125) * Migrate OpenTracing to OpenTelemetry. Breaking change to environment variable configuration. See: jaegertracing.md. --- algorithms.go | 136 +++++++++------- client.go | 13 +- cluster/cluster.go | 6 +- cmd/gubernator-cli/main.go | 120 +++++++------- cmd/gubernator/main.go | 48 ++---- daemon.go | 43 +++-- etcd.go | 29 +++- functional_test.go | 10 +- global.go | 15 +- go.mod | 78 ++++++---- go.sum | 236 +++++++++++++++------------- gubernator.go | 260 +++++++++++++++++-------------- gubernator_pool.go | 127 ++++++++------- gubernator_pool_internal_test.go | 6 +- jaegertracing.md | 103 +++++++----- peer_client.go | 228 +++++++++++++++------------ tracing/tracing.go | 92 ----------- 17 files changed, 786 insertions(+), 764 deletions(-) delete mode 100644 tracing/tracing.go diff --git a/algorithms.go b/algorithms.go index aca6458e..9bb08c3f 100644 --- a/algorithms.go +++ b/algorithms.go @@ -19,31 +19,37 @@ package gubernator import ( "context" - "github.com/mailgun/gubernator/v2/tracing" "github.com/mailgun/holster/v4/clock" + "github.com/mailgun/holster/v4/tracing" "github.com/prometheus/client_golang/prometheus" "github.com/sirupsen/logrus" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" ) // Implements token bucket algorithm for rate limiting. https://en.wikipedia.org/wiki/Token_bucket func tokenBucket(ctx context.Context, s Store, c Cache, r *RateLimitReq) (resp *RateLimitResp, err error) { - span, ctx := tracing.StartSpan(ctx) - defer span.Finish() + ctx = tracing.StartScope(ctx) + defer func() { + tracing.EndScope(ctx, err) + }() + span := trace.SpanFromContext(ctx) + tokenBucketTimer := prometheus.NewTimer(funcTimeMetric.WithLabelValues("tokenBucket")) defer tokenBucketTimer.ObserveDuration() // Get rate limit from cache. hashKey := r.HashKey() item, ok := c.GetItem(hashKey) - tracing.LogInfo(span, "c.GetItem()") + span.AddEvent("c.GetItem()") if s != nil && !ok { // Cache miss. // Check our store for the item. if item, ok = s.Get(ctx, r); ok { - tracing.LogInfo(span, "Check store for rate limit") + span.AddEvent("Check store for rate limit") c.Add(item) - tracing.LogInfo(span, "c.Add()") + span.AddEvent("c.Add()") } } @@ -51,20 +57,20 @@ func tokenBucket(ctx context.Context, s Store, c Cache, r *RateLimitReq) (resp * if ok { if item.Value == nil { msgPart := "tokenBucket: Invalid cache item; Value is nil" - tracing.LogInfo(span, msgPart, - "hashKey", hashKey, - "key", r.UniqueKey, - "name", r.Name, - ) + span.AddEvent(msgPart, trace.WithAttributes( + attribute.String("hashKey", hashKey), + attribute.String("key", r.UniqueKey), + attribute.String("name", r.Name), + )) logrus.Error(msgPart) ok = false } else if item.Key != hashKey { msgPart := "tokenBucket: Invalid cache item; key mismatch" - tracing.LogInfo(span, msgPart, - "itemKey", item.Key, - "hashKey", hashKey, - "name", r.Name, - ) + span.AddEvent(msgPart, trace.WithAttributes( + attribute.String("itemKey", item.Key), + attribute.String("hashKey", hashKey), + attribute.String("name", r.Name), + )) logrus.Error(msgPart) ok = false } @@ -72,15 +78,15 @@ func tokenBucket(ctx context.Context, s Store, c Cache, r *RateLimitReq) (resp * if ok { // Item found in cache or store. - tracing.LogInfo(span, "Update existing rate limit") + span.AddEvent("Update existing rate limit") if HasBehavior(r.Behavior, Behavior_RESET_REMAINING) { c.Remove(hashKey) - tracing.LogInfo(span, "c.Remove()") + span.AddEvent("c.Remove()") if s != nil { s.Remove(ctx, hashKey) - tracing.LogInfo(span, "s.Remove()") + span.AddEvent("s.Remove()") } return &RateLimitResp{ Status: Status_UNDER_LIMIT, @@ -98,21 +104,21 @@ func tokenBucket(ctx context.Context, s Store, c Cache, r *RateLimitReq) (resp * t, ok := item.Value.(*TokenBucketItem) if !ok { // Client switched algorithms; perhaps due to a migration? - tracing.LogInfo(span, "Client switched algorithms; perhaps due to a migration?") + span.AddEvent("Client switched algorithms; perhaps due to a migration?") c.Remove(hashKey) - tracing.LogInfo(span, "c.Remove()") + span.AddEvent("c.Remove()") if s != nil { s.Remove(ctx, hashKey) - tracing.LogInfo(span, "s.Remove()") + span.AddEvent("s.Remove()") } return tokenBucketNewItem(ctx, s, c, r) } // Update the limit if it changed. - tracing.LogInfo(span, "Update the limit if changed") + span.AddEvent("Update the limit if changed") if t.Limit != r.Limit { // Add difference to remaining. t.Remaining += r.Limit - t.Limit @@ -131,7 +137,7 @@ func tokenBucket(ctx context.Context, s Store, c Cache, r *RateLimitReq) (resp * // If the duration config changed, update the new ExpireAt. if t.Duration != r.Duration { - tracing.LogInfo(span, "Duration changed") + span.AddEvent("Duration changed") expire := t.CreatedAt + r.Duration if HasBehavior(r.Behavior, Behavior_DURATION_IS_GREGORIAN) { expire, err = GregorianExpiration(clock.Now(), r.Duration) @@ -144,7 +150,7 @@ func tokenBucket(ctx context.Context, s Store, c Cache, r *RateLimitReq) (resp * now := MillisecondNow() if expire <= now { // Renew item. - tracing.LogInfo(span, "Limit has expired") + span.AddEvent("Limit has expired") expire = now + r.Duration t.CreatedAt = now t.Remaining = t.Limit @@ -158,20 +164,20 @@ func tokenBucket(ctx context.Context, s Store, c Cache, r *RateLimitReq) (resp * if s != nil { defer func() { s.OnChange(ctx, r, item) - tracing.LogInfo(span, "defer s.OnChange()") + span.AddEvent("defer s.OnChange()") }() } // Client is only interested in retrieving the current status or // updating the rate limit config. if r.Hits == 0 { - tracing.LogInfo(span, "Return current status, apply no change") + span.AddEvent("Return current status, apply no change") return rl, nil } // If we are already at the limit. if rl.Remaining == 0 { - tracing.LogInfo(span, "Already over the limit") + span.AddEvent("Already over the limit") overLimitCounter.Add(1) rl.Status = Status_OVER_LIMIT t.Status = rl.Status @@ -180,7 +186,7 @@ func tokenBucket(ctx context.Context, s Store, c Cache, r *RateLimitReq) (resp * // If requested hits takes the remainder. if t.Remaining == r.Hits { - tracing.LogInfo(span, "At the limit") + span.AddEvent("At the limit") t.Remaining = 0 rl.Remaining = 0 return rl, nil @@ -189,13 +195,13 @@ func tokenBucket(ctx context.Context, s Store, c Cache, r *RateLimitReq) (resp * // If requested is more than available, then return over the limit // without updating the cache. if r.Hits > t.Remaining { - tracing.LogInfo(span, "Over the limit") + span.AddEvent("Over the limit") overLimitCounter.Add(1) rl.Status = Status_OVER_LIMIT return rl, nil } - tracing.LogInfo(span, "Under the limit") + span.AddEvent("Under the limit") t.Remaining -= r.Hits rl.Remaining = t.Remaining return rl, nil @@ -207,8 +213,11 @@ func tokenBucket(ctx context.Context, s Store, c Cache, r *RateLimitReq) (resp * // Called by tokenBucket() when adding a new item in the store. func tokenBucketNewItem(ctx context.Context, s Store, c Cache, r *RateLimitReq) (resp *RateLimitResp, err error) { - span, ctx := tracing.StartSpan(ctx) - defer span.Finish() + ctx = tracing.StartScope(ctx) + defer func() { + tracing.EndScope(ctx, err) + }() + span := trace.SpanFromContext(ctx) now := MillisecondNow() expire := now + r.Duration @@ -227,7 +236,7 @@ func tokenBucketNewItem(ctx context.Context, s Store, c Cache, r *RateLimitReq) } // Add a new rate limit to the cache. - tracing.LogInfo(span, "Add a new rate limit to the cache") + span.AddEvent("Add a new rate limit to the cache") if HasBehavior(r.Behavior, Behavior_DURATION_IS_GREGORIAN) { expire, err = GregorianExpiration(clock.Now(), r.Duration) if err != nil { @@ -244,7 +253,7 @@ func tokenBucketNewItem(ctx context.Context, s Store, c Cache, r *RateLimitReq) // Client could be requesting that we always return OVER_LIMIT. if r.Hits > r.Limit { - tracing.LogInfo(span, "Over the limit") + span.AddEvent("Over the limit") overLimitCounter.Add(1) rl.Status = Status_OVER_LIMIT rl.Remaining = r.Limit @@ -252,11 +261,11 @@ func tokenBucketNewItem(ctx context.Context, s Store, c Cache, r *RateLimitReq) } c.Add(item) - tracing.LogInfo(span, "c.Add()") + span.AddEvent("c.Add()") if s != nil { s.OnChange(ctx, r, item) - tracing.LogInfo(span, "s.OnChange()") + span.AddEvent("s.OnChange()") } return rl, nil @@ -264,8 +273,12 @@ func tokenBucketNewItem(ctx context.Context, s Store, c Cache, r *RateLimitReq) // Implements leaky bucket algorithm for rate limiting https://en.wikipedia.org/wiki/Leaky_bucket func leakyBucket(ctx context.Context, s Store, c Cache, r *RateLimitReq) (resp *RateLimitResp, err error) { - span, ctx := tracing.StartSpan(ctx) - defer span.Finish() + ctx = tracing.StartScope(ctx) + defer func() { + tracing.EndScope(ctx, err) + }() + span := trace.SpanFromContext(ctx) + leakyBucketTimer := prometheus.NewTimer(funcTimeMetric.WithLabelValues("V1Instance.getRateLimit_leakyBucket")) defer leakyBucketTimer.ObserveDuration() @@ -278,15 +291,15 @@ func leakyBucket(ctx context.Context, s Store, c Cache, r *RateLimitReq) (resp * // Get rate limit from cache. hashKey := r.HashKey() item, ok := c.GetItem(hashKey) - tracing.LogInfo(span, "c.GetItem()") + span.AddEvent("c.GetItem()") if s != nil && !ok { // Cache miss. // Check our store for the item. if item, ok = s.Get(ctx, r); ok { - tracing.LogInfo(span, "Check store for rate limit") + span.AddEvent("Check store for rate limit") c.Add(item) - tracing.LogInfo(span, "c.Add()") + span.AddEvent("c.Add()") } } @@ -294,20 +307,20 @@ func leakyBucket(ctx context.Context, s Store, c Cache, r *RateLimitReq) (resp * if ok { if item.Value == nil { msgPart := "leakyBucket: Invalid cache item; Value is nil" - tracing.LogInfo(span, msgPart, - "hashKey", hashKey, - "key", r.UniqueKey, - "name", r.Name, - ) + span.AddEvent(msgPart, trace.WithAttributes( + attribute.String("hashKey", hashKey), + attribute.String("key", r.UniqueKey), + attribute.String("name", r.Name), + )) logrus.Error(msgPart) ok = false } else if item.Key != hashKey { msgPart := "leakyBucket: Invalid cache item; key mismatch" - tracing.LogInfo(span, msgPart, - "itemKey", item.Key, - "hashKey", hashKey, - "name", r.Name, - ) + span.AddEvent(msgPart, trace.WithAttributes( + attribute.String("itemKey", item.Key), + attribute.String("hashKey", hashKey), + attribute.String("name", r.Name), + )) logrus.Error(msgPart) ok = false } @@ -315,17 +328,17 @@ func leakyBucket(ctx context.Context, s Store, c Cache, r *RateLimitReq) (resp * if ok { // Item found in cache or store. - tracing.LogInfo(span, "Update existing rate limit") + span.AddEvent("Update existing rate limit") b, ok := item.Value.(*LeakyBucketItem) if !ok { // Client switched algorithms; perhaps due to a migration? c.Remove(hashKey) - tracing.LogInfo(span, "c.Remove()") + span.AddEvent("c.Remove()") if s != nil { s.Remove(ctx, hashKey) - tracing.LogInfo(span, "s.Remove()") + span.AddEvent("s.Remove()") } return leakyBucketNewItem(ctx, s, c, r) @@ -396,7 +409,7 @@ func leakyBucket(ctx context.Context, s Store, c Cache, r *RateLimitReq) (resp * if s != nil { defer func() { s.OnChange(ctx, r, item) - tracing.LogInfo(span, "s.OnChange()") + span.AddEvent("s.OnChange()") }() } @@ -439,8 +452,11 @@ func leakyBucket(ctx context.Context, s Store, c Cache, r *RateLimitReq) (resp * // Called by leakyBucket() when adding a new item in the store. func leakyBucketNewItem(ctx context.Context, s Store, c Cache, r *RateLimitReq) (resp *RateLimitResp, err error) { - span, ctx := tracing.StartSpan(ctx) - defer span.Finish() + ctx = tracing.StartScope(ctx) + defer func() { + tracing.EndScope(ctx, err) + }() + span := trace.SpanFromContext(ctx) now := MillisecondNow() duration := r.Duration @@ -489,11 +505,11 @@ func leakyBucketNewItem(ctx context.Context, s Store, c Cache, r *RateLimitReq) } c.Add(item) - tracing.LogInfo(span, "c.Add()") + span.AddEvent("c.Add()") if s != nil { s.OnChange(ctx, r, item) - tracing.LogInfo(span, "s.OnChange()") + span.AddEvent("s.OnChange()") } return &rl, nil diff --git a/client.go b/client.go index 62ecdfc7..7f780ad9 100644 --- a/client.go +++ b/client.go @@ -22,9 +22,8 @@ import ( "time" "github.com/mailgun/holster/v4/clock" - otgrpc "github.com/opentracing-contrib/go-grpc" - "github.com/opentracing/opentracing-go" "github.com/pkg/errors" + "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" "google.golang.org/grpc" "google.golang.org/grpc/credentials" ) @@ -45,14 +44,10 @@ func DialV1Server(server string, tls *tls.Config) (V1Client, error) { return nil, errors.New("server is empty; must provide a server") } - // Setup Opentracing interceptor to propagate spans. - tracer := opentracing.GlobalTracer() - tracingUnaryInterceptor := otgrpc.OpenTracingClientInterceptor(tracer) - tracingStreamInterceptor := otgrpc.OpenTracingStreamClientInterceptor(tracer) - + // Setup OpenTelemetry interceptor to propagate spans. opts := []grpc.DialOption{ - grpc.WithUnaryInterceptor(tracingUnaryInterceptor), - grpc.WithStreamInterceptor(tracingStreamInterceptor), + grpc.WithUnaryInterceptor(otelgrpc.UnaryClientInterceptor()), + grpc.WithStreamInterceptor(otelgrpc.StreamClientInterceptor()), } if tls != nil { opts = append(opts, grpc.WithTransportCredentials(credentials.NewTLS(tls))) diff --git a/cluster/cluster.go b/cluster/cluster.go index 6a004958..58f83522 100644 --- a/cluster/cluster.go +++ b/cluster/cluster.go @@ -22,9 +22,9 @@ import ( "math/rand" "github.com/mailgun/gubernator/v2" - "github.com/mailgun/gubernator/v2/tracing" "github.com/mailgun/holster/v4/clock" - "github.com/pkg/errors" + "github.com/mailgun/holster/v4/ctxutil" + "github.com/mailgun/holster/v4/errors" "github.com/sirupsen/logrus" ) @@ -100,7 +100,7 @@ func Restart(ctx context.Context) error { // StartWith a local cluster with specific addresses func StartWith(localPeers []gubernator.PeerInfo) error { for _, peer := range localPeers { - ctx, cancel := tracing.ContextWithTimeout(context.Background(), clock.Second*10) + ctx, cancel := ctxutil.WithTimeout(context.Background(), clock.Second*10) d, err := gubernator.SpawnDaemon(ctx, gubernator.DaemonConfig{ Logger: logrus.WithField("instance", peer.GRPCAddress), GRPCListenAddress: peer.GRPCAddress, diff --git a/cmd/gubernator-cli/main.go b/cmd/gubernator-cli/main.go index a2a801fb..4d753291 100644 --- a/cmd/gubernator-cli/main.go +++ b/cmd/gubernator-cli/main.go @@ -27,15 +27,16 @@ import ( "github.com/davecgh/go-spew/spew" guber "github.com/mailgun/gubernator/v2" - "github.com/mailgun/gubernator/v2/tracing" "github.com/mailgun/holster/v4/clock" + "github.com/mailgun/holster/v4/ctxutil" + "github.com/mailgun/holster/v4/errors" "github.com/mailgun/holster/v4/setter" "github.com/mailgun/holster/v4/syncutil" - "github.com/opentracing/opentracing-go" - "github.com/opentracing/opentracing-go/ext" - "github.com/pkg/errors" + "github.com/mailgun/holster/v4/tracing" "github.com/sirupsen/logrus" - jaegerConfig "github.com/uber/jaeger-client-go/config" + "go.opentelemetry.io/otel/attribute" + sdktrace "go.opentelemetry.io/otel/sdk/trace" + "go.opentelemetry.io/otel/trace" "golang.org/x/time/rate" ) @@ -60,37 +61,57 @@ func main() { flag.BoolVar(&quiet, "q", false, "Quiet logging") flag.Parse() + if quiet { + log.SetLevel(logrus.ErrorLevel) + } + + // Initialize tracing. + res, err := tracing.NewResource("gubernator-cli", "") + if err != nil { + log.WithError(err).Fatal("Error in tracing.NewResource") + } ctx := context.Background() - err := initTracing() + _, _, err = tracing.InitTracing(ctx, + "github.com/mailgun/gubernator/v2/cmd/gubernator-cli", + sdktrace.WithResource(res), + ) if err != nil { - log.WithError(err).Warn("Error in initTracing") + log.WithError(err).Warn("Error in tracing.InitTracing") } - span, _ := tracing.StartSpan(ctx) // Print startup message. + startCtx := tracing.StartScope(ctx) argsMsg := fmt.Sprintf("Command line: %s", strings.Join(os.Args[1:], " ")) log.Info(argsMsg) - tracing.LogInfo(span, argsMsg) - span.Finish() + tracing.EndScope(startCtx, nil) - conf, err := guber.SetupDaemonConfig(log, configFile) - checkErr(err) - setter.SetOverride(&conf.GRPCListenAddress, grpcAddress) + var client guber.V1Client + err = tracing.Scope(ctx, func(ctx context.Context) error { + // Print startup message. + cmdLine := strings.Join(os.Args[1:], " ") + logrus.WithContext(ctx).Info("Command line: " + cmdLine) - if configFile == "" && grpcAddress == "" && os.Getenv("GUBER_GRPC_ADDRESS") == "" { - checkErr(errors.New("please provide a GRPC endpoint via -e or from a config " + - "file via -config or set the env GUBER_GRPC_ADDRESS")) - } + conf, err := guber.SetupDaemonConfig(log, configFile) + if err != nil { + return err + } + setter.SetOverride(&conf.GRPCListenAddress, grpcAddress) - if quiet { - log.SetLevel(logrus.ErrorLevel) - } + if configFile == "" && grpcAddress == "" && os.Getenv("GUBER_GRPC_ADDRESS") == "" { + return errors.New("please provide a GRPC endpoint via -e or from a config " + + "file via -config or set the env GUBER_GRPC_ADDRESS") + } - err = guber.SetupTLS(conf.TLS) - checkErr(err) + err = guber.SetupTLS(conf.TLS) + if err != nil { + return err + } + + log.WithContext(ctx).Infof("Connecting to '%s'...", conf.GRPCListenAddress) + client, err = guber.DialV1Server(conf.GRPCListenAddress, conf.ClientTLS()) + return err + }) - log.Infof("Connecting to '%s'...\n", conf.GRPCListenAddress) - client, err := guber.DialV1Server(conf.GRPCListenAddress, conf.ClientTLS()) checkErr(err) // Generate a selection of rate limits with random limits. @@ -156,26 +177,26 @@ func randInt(min, max int) int { } func sendRequest(ctx context.Context, client guber.V1Client, req *guber.GetRateLimitsReq) { - span, ctx := tracing.StartSpan(ctx) - defer span.Finish() - ctx, cancel := tracing.ContextWithTimeout(ctx, timeout) + ctx = tracing.StartScope(ctx) + defer tracing.EndScope(ctx, nil) + + ctx, cancel := ctxutil.WithTimeout(ctx, timeout) // Now hit our cluster with the rate limits resp, err := client.GetRateLimits(ctx, req) cancel() if err != nil { - ext.LogError(span, errors.Wrap(err, "Error in client.GetRateLimits")) - log.WithError(err).Error("Error in client.GetRateLimits") + log.WithContext(ctx).WithError(err).Error("Error in client.GetRateLimits") return } // Sanity checks. if resp == nil { - log.Error("Response object is unexpectedly nil") + log.WithContext(ctx).Error("Response object is unexpectedly nil") return } if resp.Responses == nil { - log.Error("Responses array is unexpectedly nil") + log.WithContext(ctx).Error("Responses array is unexpectedly nil") return } @@ -185,39 +206,20 @@ func sendRequest(ctx context.Context, client guber.V1Client, req *guber.GetRateL for itemNum, resp := range resp.Responses { if resp.Status == guber.Status_OVER_LIMIT { overlimit = true - log.WithField("name", req.Requests[itemNum].Name).Info("Overlimit!") + log.WithContext(ctx).WithField("name", req.Requests[itemNum].Name). + Info("Overlimit!") } } if overlimit { - span.SetTag("overlimit", true) + span := trace.SpanFromContext(ctx) + span.SetAttributes( + attribute.Bool("overlimit", true), + ) + if !quiet { - log.Info(spew.Sdump(resp)) + dumpResp := spew.Sdump(resp) + log.WithContext(ctx).Info(dumpResp) } } } - -// Configure tracer and set as global tracer. -// Be sure to call closer.Close() on application exit. -func initTracing() error { - // Configure new tracer. - cfg, err := jaegerConfig.FromEnv() - if err != nil { - return errors.Wrap(err, "Error in jaeger.FromEnv()") - } - if cfg.ServiceName == "" { - cfg.ServiceName = "gubernator-cli" - } - - var tracer opentracing.Tracer - - tracer, _, err = cfg.NewTracer() - if err != nil { - return errors.Wrap(err, "Error in cfg.NewTracer") - } - - // Set as global tracer. - opentracing.SetGlobalTracer(tracer) - - return nil -} diff --git a/cmd/gubernator/main.go b/cmd/gubernator/main.go index ee9ffaae..f0e5b3cf 100644 --- a/cmd/gubernator/main.go +++ b/cmd/gubernator/main.go @@ -26,12 +26,11 @@ import ( "syscall" "github.com/mailgun/gubernator/v2" - "github.com/mailgun/gubernator/v2/tracing" "github.com/mailgun/holster/v4/clock" - "github.com/opentracing/opentracing-go" - "github.com/pkg/errors" + "github.com/mailgun/holster/v4/ctxutil" + "github.com/mailgun/holster/v4/tracing" "github.com/sirupsen/logrus" - jaegerConfig "github.com/uber/jaeger-client-go/config" + sdktrace "go.opentelemetry.io/otel/sdk/trace" "k8s.io/klog" ) @@ -55,16 +54,25 @@ func main() { klog.InitFlags(nil) flag.Set("logtostderr", "true") - err := initTracing() + // Initialize tracing. + res, err := tracing.NewResource("gubernator", Version) if err != nil { - log.WithError(err).Warn("Error in initTracing") + log.WithError(err).Fatal("Error in tracing.NewResource") + } + + ctx, _, err := tracing.InitTracing(context.Background(), + "github.com/mailgun/gubernator/v2", + sdktrace.WithResource(res), + ) + if err != nil { + log.WithError(err).Warn("Error in tracing.InitTracing") } // Read our config from the environment or optional environment config file conf, err := gubernator.SetupDaemonConfig(logrus.StandardLogger(), configFile) checkErr(err, "while getting config") - ctx, cancel := tracing.ContextWithTimeout(context.Background(), clock.Second*10) + ctx, cancel := ctxutil.WithTimeout(ctx, clock.Second*10) defer cancel() // Start the daemon @@ -78,6 +86,7 @@ func main() { for range c { log.Info("caught signal; shutting down") daemon.Close() + tracing.CloseTracing(context.Background()) exit(0) } } @@ -95,28 +104,3 @@ func exit(code int) { } os.Exit(code) } - -// Configure tracer and set as global tracer. -// Be sure to call closer.Close() on application exit. -func initTracing() error { - // Configure new tracer. - cfg, err := jaegerConfig.FromEnv() - if err != nil { - return errors.Wrap(err, "Error in jaeger.FromEnv()") - } - if cfg.ServiceName == "" { - cfg.ServiceName = "gubernator" - } - - var tracer opentracing.Tracer - - tracer, tracerCloser, err = cfg.NewTracer() - if err != nil { - return errors.Wrap(err, "Error in cfg.NewTracer") - } - - // Set as global tracer. - opentracing.SetGlobalTracer(tracer) - - return nil -} diff --git a/daemon.go b/daemon.go index 42d5c69b..69ad3224 100644 --- a/daemon.go +++ b/daemon.go @@ -26,17 +26,16 @@ import ( "time" "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" - "github.com/mailgun/gubernator/v2/tracing" + "github.com/mailgun/holster/v4/errors" "github.com/mailgun/holster/v4/etcdutil" "github.com/mailgun/holster/v4/setter" "github.com/mailgun/holster/v4/syncutil" - otgrpc "github.com/opentracing-contrib/go-grpc" - "github.com/opentracing/opentracing-go" - "github.com/pkg/errors" + "github.com/mailgun/holster/v4/tracing" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/collectors" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/sirupsen/logrus" + "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" "google.golang.org/grpc" "google.golang.org/grpc/credentials" "google.golang.org/grpc/keepalive" @@ -65,19 +64,19 @@ type Daemon struct { // This function will block until the daemon responds to connections as specified // by GRPCListenAddress and HTTPListenAddress func SpawnDaemon(ctx context.Context, conf DaemonConfig) (*Daemon, error) { - span, ctx := tracing.StartSpan(ctx) - defer span.Finish() + var s *Daemon - s := Daemon{ - log: conf.Logger, - conf: conf, - } - setter.SetDefault(&s.log, logrus.WithField("category", "gubernator")) + err := tracing.Scope(ctx, func(ctx context.Context) error { + s = &Daemon{ + log: conf.Logger, + conf: conf, + } + setter.SetDefault(&s.log, logrus.WithField("category", "gubernator")) - if err := s.Start(ctx); err != nil { - return nil, err - } - return &s, nil + return s.Start(ctx) + }) + + return s, err } func (s *Daemon) Start(ctx context.Context) error { @@ -102,6 +101,10 @@ func (s *Daemon) Start(ctx context.Context) error { opts := []grpc.ServerOption{ grpc.StatsHandler(s.statsHandler), grpc.MaxRecvMsgSize(1024 * 1024), + + // OpenTelemetry instrumentation on gRPC endpoints. + grpc.UnaryInterceptor(otelgrpc.UnaryServerInterceptor()), + grpc.StreamInterceptor(otelgrpc.StreamServerInterceptor()), } if s.conf.GRPCMaxConnectionAgeSeconds > 0 { @@ -115,16 +118,6 @@ func (s *Daemon) Start(ctx context.Context) error { return err } - // Opentracing on gRPC endpoints. - tracer := opentracing.GlobalTracer() - tracingUnaryInterceptor := otgrpc.OpenTracingServerInterceptor(tracer) - tracingStreamInterceptor := otgrpc.OpenTracingStreamServerInterceptor(tracer) - - opts = append(opts, - grpc.UnaryInterceptor(tracingUnaryInterceptor), - grpc.StreamInterceptor(tracingStreamInterceptor), - ) - if s.conf.ServerTLS() != nil { // Create two GRPC server instances, one for TLS and the other for the API Gateway opts2 := append(opts, grpc.Creds(credentials.NewTLS(s.conf.ServerTLS()))) diff --git a/etcd.go b/etcd.go index c5d619f4..717624da 100644 --- a/etcd.go +++ b/etcd.go @@ -20,11 +20,11 @@ import ( "context" "encoding/json" - "github.com/mailgun/gubernator/v2/tracing" "github.com/mailgun/holster/v4/clock" + "github.com/mailgun/holster/v4/ctxutil" + "github.com/mailgun/holster/v4/errors" "github.com/mailgun/holster/v4/setter" "github.com/mailgun/holster/v4/syncutil" - "github.com/pkg/errors" "github.com/sirupsen/logrus" etcd "go.etcd.io/etcd/client/v3" ) @@ -139,7 +139,7 @@ func (e *EtcdPool) watchPeers() error { } func (e *EtcdPool) collectPeers(revision *int64) error { - ctx, cancel := tracing.ContextWithTimeout(e.ctx, etcdTimeout) + ctx, cancel := ctxutil.WithTimeout(e.ctx, etcdTimeout) defer cancel() resp, err := e.conf.Client.Get(ctx, e.conf.KeyPrefix, etcd.WithPrefix()) @@ -232,7 +232,7 @@ func (e *EtcdPool) register(peer PeerInfo) error { var lease *etcd.LeaseGrantResponse register := func() error { - ctx, cancel := tracing.ContextWithTimeout(e.ctx, etcdTimeout) + ctx, cancel := ctxutil.WithTimeout(e.ctx, etcdTimeout) defer cancel() var err error @@ -296,7 +296,7 @@ func (e *EtcdPool) register(peer PeerInfo) error { } lastKeepAlive = clock.Now() case <-done: - ctx, cancel := tracing.ContextWithTimeout(context.Background(), etcdTimeout) + ctx, cancel := ctxutil.WithTimeout(context.Background(), etcdTimeout) if _, err := e.conf.Client.Delete(ctx, instanceKey); err != nil { e.log.WithError(err). Warn("during etcd delete") @@ -332,3 +332,22 @@ func (e *EtcdPool) callOnUpdate() { e.conf.OnUpdate(peers) } + +// Get peers list from etcd. +func (e *EtcdPool) GetPeers(ctx context.Context) ([]PeerInfo, error) { + keyPrefix := e.conf.KeyPrefix + + resp, err := e.conf.Client.Get(ctx, keyPrefix, etcd.WithPrefix()) + if err != nil { + return nil, errors.Wrapf(err, "while fetching peer listing from '%s'", keyPrefix) + } + + var peers []PeerInfo + + for _, v := range resp.Kvs { + p := e.unMarshallValue(v.Value) + peers = append(peers, p) + } + + return peers, nil +} diff --git a/functional_test.go b/functional_test.go index 32849b55..ece70a50 100644 --- a/functional_test.go +++ b/functional_test.go @@ -1048,13 +1048,13 @@ func TestGetPeerRateLimits(t *testing.T) { } for i := 0; i < n; i++ { req.Requests[i] = &gubernator.RateLimitReq{ - Name: "Foobar", + Name: "Foobar", UniqueKey: fmt.Sprintf("%08x", i), - Hits: 0, - Limit: 1000 + int64(i), - Duration: 1000, + Hits: 0, + Limit: 1000 + int64(i), + Duration: 1000, Algorithm: gubernator.Algorithm_TOKEN_BUCKET, - Behavior: gubernator.Behavior_BATCHING, + Behavior: gubernator.Behavior_BATCHING, } } diff --git a/global.go b/global.go index d9f77c62..1e31ff84 100644 --- a/global.go +++ b/global.go @@ -20,9 +20,10 @@ import ( "context" "time" - "github.com/mailgun/gubernator/v2/tracing" "github.com/mailgun/holster/v4/clock" + "github.com/mailgun/holster/v4/ctxutil" "github.com/mailgun/holster/v4/syncutil" + "github.com/mailgun/holster/v4/tracing" "github.com/prometheus/client_golang/prometheus" "github.com/sirupsen/logrus" "google.golang.org/protobuf/proto" @@ -80,8 +81,8 @@ func (gm *globalManager) runAsyncHits() { hits := make(map[string]*RateLimitReq) gm.wg.Until(func(done chan struct{}) bool { - span, ctx := tracing.StartSpan(context.Background()) - defer span.Finish() + ctx := tracing.StartScope(context.Background()) + defer tracing.EndScope(ctx, nil) select { case r := <-gm.asyncQueue: @@ -150,7 +151,7 @@ func (gm *globalManager) sendHits(ctx context.Context, hits map[string]*RateLimi // Send the rate limit requests to their respective owning peers. for _, p := range peerRequests { - ctx, cancel := tracing.ContextWithTimeout(context.Background(), gm.conf.GlobalTimeout) + ctx, cancel := ctxutil.WithTimeout(context.Background(), gm.conf.GlobalTimeout) _, err := p.client.GetPeerRateLimits(ctx, &p.req) cancel() @@ -169,8 +170,8 @@ func (gm *globalManager) runBroadcasts() { updates := make(map[string]*RateLimitReq) gm.wg.Until(func(done chan struct{}) bool { - span, ctx := tracing.StartSpan(context.Background()) - defer span.Finish() + ctx := tracing.StartScope(context.Background()) + defer tracing.EndScope(ctx, nil) select { case r := <-gm.broadcastQueue: @@ -233,7 +234,7 @@ func (gm *globalManager) broadcastPeers(ctx context.Context, updates map[string] continue } - ctx, cancel := tracing.ContextWithTimeout(context.Background(), gm.conf.GlobalTimeout) + ctx, cancel := ctxutil.WithTimeout(context.Background(), gm.conf.GlobalTimeout) _, err := peer.UpdatePeerGlobals(ctx, &req) cancel() diff --git a/go.mod b/go.mod index 8732a48e..814a001c 100644 --- a/go.mod +++ b/go.mod @@ -6,25 +6,28 @@ require ( github.com/OneOfOne/xxhash v1.2.8 github.com/davecgh/go-spew v1.1.1 github.com/grpc-ecosystem/grpc-gateway/v2 v2.5.0 - github.com/hashicorp/memberlist v0.2.4 - github.com/mailgun/holster/v4 v4.0.0 - github.com/miekg/dns v1.1.43 - github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e - github.com/opentracing/opentracing-go v1.2.0 + github.com/hashicorp/memberlist v0.3.1 + github.com/mailgun/holster/v4 v4.3.3 + github.com/miekg/dns v1.1.49 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.12.1 github.com/prometheus/client_model v0.2.0 github.com/prometheus/common v0.32.1 github.com/segmentio/fasthash v1.0.2 github.com/sirupsen/logrus v1.8.1 - github.com/stretchr/testify v1.7.0 - github.com/uber/jaeger-client-go v2.29.1+incompatible - go.etcd.io/etcd/client/v3 v3.5.0 - golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd + github.com/stretchr/testify v1.8.0 + go.etcd.io/etcd/client/v3 v3.5.4 + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.33.0 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.33.0 + go.opentelemetry.io/otel v1.8.0 + go.opentelemetry.io/otel/sdk v1.7.0 + go.opentelemetry.io/otel/trace v1.8.0 + golang.org/x/net v0.0.0-20220607020251-c690dde0001d golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac - google.golang.org/genproto v0.0.0-20210617175327-b9e0b3197ced - google.golang.org/grpc v1.39.0 - google.golang.org/protobuf v1.27.1 + google.golang.org/api v0.43.0 + google.golang.org/genproto v0.0.0-20220607140733-d738665f6195 + google.golang.org/grpc v1.47.0 + google.golang.org/protobuf v1.28.0 k8s.io/api v0.23.3 k8s.io/apimachinery v0.23.3 k8s.io/client-go v0.23.3 @@ -32,25 +35,29 @@ require ( ) require ( - github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect - github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da // indirect + cloud.google.com/go v0.81.0 // indirect + github.com/armon/go-metrics v0.4.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/coreos/go-semver v0.3.0 // indirect github.com/coreos/go-systemd/v22 v22.3.2 // indirect - github.com/go-logr/logr v1.2.0 // indirect + github.com/felixge/httpsnoop v1.0.3 // indirect + github.com/go-logr/logr v1.2.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.2 // indirect - github.com/google/btree v1.0.1 // indirect - github.com/google/go-cmp v0.5.6 // indirect + github.com/google/btree v1.1.1 // indirect + github.com/google/go-cmp v0.5.8 // indirect github.com/google/gofuzz v1.1.0 // indirect + github.com/googleapis/gax-go/v2 v2.0.5 // indirect github.com/googleapis/gnostic v0.5.5 // indirect - github.com/hashicorp/errwrap v1.0.0 // indirect - github.com/hashicorp/go-immutable-radix v1.0.0 // indirect - github.com/hashicorp/go-msgpack v0.5.3 // indirect - github.com/hashicorp/go-multierror v1.1.0 // indirect - github.com/hashicorp/go-sockaddr v1.0.0 // indirect - github.com/hashicorp/golang-lru v0.5.1 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-msgpack v1.1.5 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/imdario/mergo v0.3.5 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect @@ -60,21 +67,28 @@ require ( github.com/prometheus/procfs v0.7.3 // indirect github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/stretchr/objx v0.1.1 // indirect - github.com/uber/jaeger-lib v2.4.1+incompatible // indirect - go.etcd.io/etcd/api/v3 v3.5.0 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.5.0 // indirect - go.uber.org/atomic v1.7.0 // indirect - go.uber.org/multierr v1.6.0 // indirect - go.uber.org/zap v1.17.0 // indirect + github.com/stretchr/objx v0.4.0 // indirect + github.com/uptrace/opentelemetry-go-extra/otellogrus v0.1.14 // indirect + github.com/uptrace/opentelemetry-go-extra/otelutil v0.1.14 // indirect + go.etcd.io/etcd/api/v3 v3.5.4 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.5.4 // indirect + go.opencensus.io v0.23.0 // indirect + go.opentelemetry.io/otel/exporters/jaeger v1.7.0 // indirect + go.opentelemetry.io/otel/metric v0.31.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.8.0 // indirect + go.uber.org/zap v1.21.0 // indirect + golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f // indirect - golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect + golang.org/x/sys v0.0.0-20220608164250-635b8c9b7f68 // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/text v0.3.7 // indirect + golang.org/x/tools v0.1.10 // indirect + golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect google.golang.org/appengine v1.6.7 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/klog/v2 v2.30.0 // indirect k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect k8s.io/utils v0.0.0-20211116205334-6203023598ed // indirect diff --git a/go.sum b/go.sum index 17ecfef0..05b95001 100644 --- a/go.sum +++ b/go.sum @@ -17,6 +17,7 @@ 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/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= @@ -45,30 +46,27 @@ github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZ github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM= -github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8= github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/Shopify/toxiproxy v2.1.4+incompatible h1:TKdv8HiTLgE5wdJuEML90aBgNWsokNbMijUGhmcoBJc= -github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/ahmetb/go-linq v3.0.0+incompatible h1:qQkjjOXKrKOTy83X8OpRmnKflXKQIL/mC/gMVVDMhOA= -github.com/ahmetb/go-linq v3.0.0+incompatible/go.mod h1:PFffvbdbtw+QTB0WKRP0cNht7vnCfnGlEpak/DVg5cY= -github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-metrics v0.4.0 h1:yCQqn7dwca4ITXb+CbubHmedzaQYHhNhrEXLYUeEe8Q= +github.com/armon/go-metrics v0.4.0/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -81,11 +79,16 @@ github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= @@ -104,12 +107,12 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= -github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= +github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -128,8 +131,12 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= 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 v1.2.0 h1:QK40JKJyMdUDz+h+xvCsru/bJhvG0UxvePV0ufL/AcE= 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-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= @@ -139,13 +146,13 @@ github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5x github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v0.0.0-20210429001901-424d2337a529 h1:2voWjNECnrZRbfwXxHB1/j8wa6xdKn85B5NzgVL/pTU= github.com/golang/glog v0.0.0-20210429001901-424d2337a529/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -175,8 +182,9 @@ 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/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -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/btree v1.1.1 h1:OMJCfqwmbcwNihVCadalGMZiHclz5T0mRv12gnIaV0Q= +github.com/google/btree v1.1.1/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= 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= @@ -188,8 +196,10 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= 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/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -208,9 +218,10 @@ github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= 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/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= @@ -220,41 +231,34 @@ github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB7 github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.5.0 h1:ajue7SzQMywqRjg2fK7dcpc0QhFGpTR2plWfV4EZWR4= github.com/grpc-ecosystem/grpc-gateway/v2 v2.5.0/go.mod h1:r1hZAcvfFXuYmcKyCJI9wlyOPIZUJl6FCB8Cpca/NLE= -github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw= -github.com/hashicorp/consul/api v1.8.1/go.mod h1:sDjTOq0yUyv5G4h+BqSea7Fn6BU+XbolEz1952UB+mk= -github.com/hashicorp/consul/sdk v0.7.0/go.mod h1:fY08Y9z5SvJqevyZNy6WWPXiG3KwBPAvlcdx16zZ0fM= -github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-hclog v0.16.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqkZzoD4= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-msgpack v1.1.5 h1:9byZdVjKTe5mce63pRVNP1L7UAmdHOTEMGehn6KvJWs= +github.com/hashicorp/go-msgpack v1.1.5/go.mod h1:gWVc3sv/wbDmR3rQsj1CAktEZzoz1YNK9NfGLXJ69/4= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= -github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= -github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= -github.com/hashicorp/go-sockaddr v1.0.0 h1:GeH6tui99pF4NJgfnhp+L6+FfobzVW3Ah46sLo0ICXs= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.0 h1:RS8zrF7PhGwyNPOtxSClXXj9HA8feRnJzgnI1RJCSnM= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= -github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= -github.com/hashicorp/memberlist v0.2.4 h1:OOhYzSvFnkFQXm1ysE8RjXTHsqSRDyP4emusC9K7DYg= -github.com/hashicorp/memberlist v0.2.4/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= -github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/memberlist v0.3.1 h1:MXgUXLqva1QvpVEDQW1IQLG0wivQAtmFlHRQ+1vWZfM= +github.com/hashicorp/memberlist v0.3.1/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -262,6 +266,7 @@ github.com/imdario/mergo v0.3.5 h1:JboBksRwiiAJWvIYJVo46AfV+IAIKZpfrSzVKj42R4Q= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -270,7 +275,6 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -282,29 +286,19 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mailgun/holster/v4 v4.0.0 h1:agmjX6skCovLK+2FRk34Dx9L6DzBldTnT7jUMTR/UYA= -github.com/mailgun/holster/v4 v4.0.0/go.mod h1:3Gavxi9KJwRAcA7UkZcDl2YOGp4Hyy3Mmdq7UCayCpM= +github.com/mailgun/holster/v4 v4.3.3 h1:xPICpmuLkcv2cim/vkJpVR/Fp+Dt6i5fGk+/FgeHlMg= +github.com/mailgun/holster/v4 v4.3.3/go.mod h1:ifiEC4i9X1CG4IehdY8smOohrSZAvdJ6UBwUnWHWHOE= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= -github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= -github.com/miekg/dns v1.1.42/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= -github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg= -github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= -github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/miekg/dns v1.1.49 h1:qe0mQU3Z/XpFeE+AEBo2rqaS1IPBJ3anmqZ4XiZJVG8= +github.com/miekg/dns v1.1.49/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -331,13 +325,9 @@ github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGV github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e h1:4cPxUYdgaGzZIT5/j0IfqOrrXmq6bG8AwvwisMXpdrg= -github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e/go.mod h1:DYR5Eij8rJl8h7gblRrOZ8g0kW1umSpKqYIBTgeDtLo= -github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= -github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c h1:Lgl0gzECD8GnQ5QCWA8o6BtfL6mDH5rQgM4/fX3avOs= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -346,11 +336,12 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -359,19 +350,21 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1: github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/segmentio/fasthash v1.0.2 h1:86fGDl2hB+iSHYlccB/FP9qRGvLNuH/fhEEFn6gnQUs= @@ -386,46 +379,71 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/uber/jaeger-client-go v2.29.1+incompatible h1:R9ec3zO3sGpzs0abd43Y+fBZRJ9uiH6lXyR/+u6brW4= -github.com/uber/jaeger-client-go v2.29.1+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= -github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg= -github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/uptrace/opentelemetry-go-extra/otellogrus v0.1.14 h1:wr4qKY3KUDcltzKTQJ/tOuUhUnY4zbDnHoAq13e+ZnY= +github.com/uptrace/opentelemetry-go-extra/otellogrus v0.1.14/go.mod h1:AgwK/cKYxv+JQyaBf1lG5YBA9zdG1EDlqjgrIXJPMc8= +github.com/uptrace/opentelemetry-go-extra/otelutil v0.1.14 h1:vuYn+33yx7KrzmnUH2TYmapR8B8DwO0nRIluc0gRdfE= +github.com/uptrace/opentelemetry-go-extra/otelutil v0.1.14/go.mod h1:vNmY7gwoy9t4RQxhmYHV1Myt4qf2bSMpSgmzFKuoZDg= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.etcd.io/etcd/api/v3 v3.5.0 h1:GsV3S+OfZEOCNXdtNkBSR7kgLobAa/SO6tCxRa0GAYw= -go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= -go.etcd.io/etcd/client/pkg/v3 v3.5.0 h1:2aQv6F436YnN7I4VbI8PPYrBhu+SmrTaADcf8Mi/6PU= -go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/v3 v3.5.0 h1:62Eh0XOro+rDwkrypAGDfgmNh5Joq+z+W9HZdlXMzek= -go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= +go.etcd.io/etcd/api/v3 v3.5.4 h1:OHVyt3TopwtUQ2GKdd5wu3PmmipR4FTwCqoEjSyRdIc= +go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A= +go.etcd.io/etcd/client/pkg/v3 v3.5.4 h1:lrneYvz923dvC14R54XcA7FXoZ3mlGZAgmwhfm7HqOg= +go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v3 v3.5.4 h1:p83BUL3tAYS0OT/r0qglgc3M1JjhM0diV8DSWAhVXv4= +go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 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/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.33.0 h1:z6rnla1Asjzn0FrhohzIbDi4bxbtc6EMmQ7f5ZPn+pA= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.33.0/go.mod h1:y/SlJpJQPd2UzfBCj0E9Flk9FDCtTyqUmaCB41qFrWI= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.33.0 h1:Z0lVKLXU+jxGf3ANoh+UWx9Ai5bjpQVnZXI1zEzvqS0= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.33.0/go.mod h1:U5rUt7Rw6zuORsWNfpMRy8XMNKLrmIlv/4HgLVW/d5M= +go.opentelemetry.io/otel v1.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+nrD5xk= +go.opentelemetry.io/otel v1.8.0 h1:zcvBFizPbpa1q7FehvFiHbQwGzmPILebO0tyqIR5Djg= +go.opentelemetry.io/otel v1.8.0/go.mod h1:2pkj+iMj0o03Y+cW6/m8Y4WkRdYN3AvCXCnzRMp9yvM= +go.opentelemetry.io/otel/exporters/jaeger v1.7.0 h1:wXgjiRldljksZkZrldGVe6XrG9u3kYDyQmkZwmm5dI0= +go.opentelemetry.io/otel/exporters/jaeger v1.7.0/go.mod h1:PwQAOqBgqbLQRKlj466DuD2qyMjbtcPpfPfj+AqbSBs= +go.opentelemetry.io/otel/metric v0.31.0 h1:6SiklT+gfWAwWUR0meEMxQBtihpiEs4c+vL9spDTqUs= +go.opentelemetry.io/otel/metric v0.31.0/go.mod h1:ohmwj9KTSIeBnDBm/ZwH2PSZxZzoOaG2xZeekTRzL5A= +go.opentelemetry.io/otel/sdk v1.7.0 h1:4OmStpcKVOfvDOgCt7UriAPtKolwIhxpnSNI/yK+1B0= +go.opentelemetry.io/otel/sdk v1.7.0/go.mod h1:uTEOTwaqIVuTGiJN7ii13Ibp75wJmYUDe374q6cZwUU= +go.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48yyE4TNvoHqU= +go.opentelemetry.io/otel/trace v1.8.0 h1:cSy0DF9eGI5WIfNwZ1q2iUyGj00tGzP24dE1lOlHrfY= +go.opentelemetry.io/otel/trace v1.8.0/go.mod h1:0Bt3PXY8w+3pheS3hQUt+wow8b1ojPaTBoTCh2zIFI4= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +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.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U= +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/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -434,10 +452,7 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= @@ -447,7 +462,6 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -473,10 +487,11 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -490,7 +505,6 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190921015927-1a5e07d1ff72/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -516,9 +530,10 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= 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= golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d h1:4SFsTMi4UahlKoloni7L4eYzhFRifURQLw+yv0QDCx8= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -550,10 +565,8 @@ golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -567,16 +580,13 @@ golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -599,20 +609,21 @@ golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/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-20210603081109-ebe580a85c40/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-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220608164250-635b8c9b7f68 h1:z8Hj/bl9cOV2grsOpEaQFUaly0JWN3i97mo3jXKJNp0= +golang.org/x/sys v0.0.0-20220608164250-635b8c9b7f68/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= @@ -632,14 +643,13 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190424220101-1e8e1cfdf96b/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -687,15 +697,15 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= 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.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= -gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= -gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= -gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df h1:5Pf6pFKu98ODmgnpvkJ3kFUOQGGLIzLIkbzUHp47618= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -716,6 +726,7 @@ google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= 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 h1:4sAyIHT6ZohtAQDoxws+ez7bROYmUlOVvsUscYCDTqA= google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -767,13 +778,13 @@ google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6D 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-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210617175327-b9e0b3197ced h1:c5geK1iMU3cDKtFrCVQIcjR3W+JOZMuhIyICMCTbtus= google.golang.org/genproto v0.0.0-20210617175327-b9e0b3197ced/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20220607140733-d738665f6195 h1:dp5xvm3zUH+xcW+Pv1o+1phiOKLVAUA4Y2zSmvDRiRA= +google.golang.org/genproto v0.0.0-20220607140733-d738665f6195/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= @@ -790,8 +801,8 @@ google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG 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.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.39.0 h1:Klz8I9kdtkIN6EpHHUOMLCYhTn/2WAe5a0s1hcBkdTI= -google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.47.0 h1:9n77onPX5F3qfFCqjy9dhn8PbNQsIKeVU04J9G7umt8= +google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= 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= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -804,8 +815,9 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 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 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= 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= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -829,8 +841,9 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -857,7 +870,6 @@ k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/ k8s.io/utils v0.0.0-20211116205334-6203023598ed h1:ck1fRPWPJWsMd8ZRFsWc6mh/zHp5fZ/shhbrgPUxDAE= k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 h1:fD1pz4yfdADVNfFmcP2aBEtudwUQ1AlLnRBALr33v3s= diff --git a/gubernator.go b/gubernator.go index 93525f6e..684e72d4 100644 --- a/gubernator.go +++ b/gubernator.go @@ -23,13 +23,15 @@ import ( "sync" "sync/atomic" - "github.com/mailgun/gubernator/v2/tracing" + "github.com/mailgun/holster/v4/ctxutil" + "github.com/mailgun/holster/v4/errors" "github.com/mailgun/holster/v4/setter" "github.com/mailgun/holster/v4/syncutil" - "github.com/opentracing/opentracing-go/ext" - "github.com/pkg/errors" + "github.com/mailgun/holster/v4/tracing" "github.com/prometheus/client_golang/prometheus" "github.com/sirupsen/logrus" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "google.golang.org/protobuf/proto" @@ -112,10 +114,11 @@ var batchSendDurationMetric = prometheus.NewSummaryVec(prometheus.SummaryOpts{ // NewV1Instance instantiate a single instance of a gubernator peer and registers this // instance with the provided GRPCServer. -func NewV1Instance(conf Config) (*V1Instance, error) { - span, ctx := tracing.StartSpan(context.Background()) - ext.SamplingPriority.Set(span, 1) - defer span.Finish() +func NewV1Instance(conf Config) (retval *V1Instance, reterr error) { + ctx := tracing.StartScope(context.Background()) + defer func() { + tracing.EndScope(ctx, reterr) + }() if conf.GRPCServers == nil { return nil, errors.New("at least one GRPCServer instance is required") @@ -153,10 +156,11 @@ func NewV1Instance(conf Config) (*V1Instance, error) { return &s, nil } -func (s *V1Instance) Close() error { - span, ctx := tracing.StartSpan(context.Background()) - ext.SamplingPriority.Set(span, 1) - defer span.Finish() +func (s *V1Instance) Close() (reterr error) { + ctx := tracing.StartScope(context.Background()) + defer func() { + tracing.EndScope(ctx, reterr) + }() if s.isClosed { return nil @@ -171,13 +175,17 @@ func (s *V1Instance) Close() error { err := s.gubernatorPool.Store(ctx) if err != nil { - logrus.WithError(err).Error("Error in checkHandlerPool.Store") + logrus.WithContext(ctx). + WithError(err). + Error("Error in checkHandlerPool.Store") return errors.Wrap(err, "Error in checkHandlerPool.Store") } err = s.gubernatorPool.Close() if err != nil { - logrus.WithError(err).Error("Error in checkHandlerPool.Close") + logrus.WithContext(ctx). + WithError(err). + Error("Error in checkHandlerPool.Close") return errors.Wrap(err, "Error in checkHandlerPool.Close") } @@ -188,16 +196,19 @@ func (s *V1Instance) Close() error { // GetRateLimits is the public interface used by clients to request rate limits from the system. If the // rate limit `Name` and `UniqueKey` is not owned by this instance then we forward the request to the // peer that does. -func (s *V1Instance) GetRateLimits(ctx context.Context, r *GetRateLimitsReq) (*GetRateLimitsResp, error) { - span, ctx := tracing.StartSpan(ctx) - defer span.Finish() +func (s *V1Instance) GetRateLimits(ctx context.Context, r *GetRateLimitsReq) (retval *GetRateLimitsResp, reterr error) { + ctx = tracing.StartScope(ctx) + defer func() { + tracing.EndScope(ctx, reterr) + }() + span := trace.SpanFromContext(ctx) funcTimer := prometheus.NewTimer(funcTimeMetric.WithLabelValues("V1Instance.GetRateLimits")) defer funcTimer.ObserveDuration() concurrentCounter := atomic.AddInt64(&s.getRateLimitsCounter, 1) defer atomic.AddInt64(&s.getRateLimitsCounter, -1) - span.SetTag("concurrentCounter", concurrentCounter) + span.SetAttributes(attribute.Int64("concurrentCounter", concurrentCounter)) concurrentChecksMetric.Observe(float64(concurrentCounter)) if len(r.Requests) > maxBatchSize { @@ -215,10 +226,7 @@ func (s *V1Instance) GetRateLimits(ctx context.Context, r *GetRateLimitsReq) (*G // For each item in the request body for i, req := range r.Requests { - span2, ctx2 := tracing.StartNamedSpan(ctx, "Iterate requests") - - func() { - defer span2.Finish() + _ = tracing.NamedScope(ctx, "Iterate requests", func(ctx context.Context) error { key := req.Name + "_" + req.UniqueKey var peer *PeerClient var err error @@ -226,32 +234,32 @@ func (s *V1Instance) GetRateLimits(ctx context.Context, r *GetRateLimitsReq) (*G if len(req.UniqueKey) == 0 { checkErrorCounter.WithLabelValues("Invalid request").Add(1) resp.Responses[i] = &RateLimitResp{Error: "field 'unique_key' cannot be empty"} - return + return nil } if len(req.Name) == 0 { checkErrorCounter.WithLabelValues("Invalid request").Add(1) resp.Responses[i] = &RateLimitResp{Error: "field 'namespace' cannot be empty"} - return + return nil } - if ctx2.Err() != nil { - err = errors.Wrap(ctx2.Err(), "Error while iterating request items") - ext.LogError(span, err) + if ctx.Err() != nil { + err = errors.Wrap(ctx.Err(), "Error while iterating request items") + span.RecordError(err) resp.Responses[i] = &RateLimitResp{ Error: err.Error(), } - return + return nil } - peer, err = s.GetPeer(ctx2, key) + peer, err = s.GetPeer(ctx, key) if err != nil { countError(err, "Error in GetPeer") err = errors.Wrapf(err, "Error in GetPeer, looking up peer that owns rate limit '%s'", key) resp.Responses[i] = &RateLimitResp{ Error: err.Error(), } - return + return nil } // If our server instance is the owner of this rate limit @@ -259,31 +267,31 @@ func (s *V1Instance) GetRateLimits(ctx context.Context, r *GetRateLimitsReq) (*G // Apply our rate limit algorithm to the request getRateLimitCounter.WithLabelValues("local").Add(1) funcTimer1 := prometheus.NewTimer(funcTimeMetric.WithLabelValues("V1Instance.getRateLimit (local)")) - resp.Responses[i], err = s.getRateLimit(ctx2, req) + resp.Responses[i], err = s.getRateLimit(ctx, req) funcTimer1.ObserveDuration() if err != nil { - err2 := errors.Wrapf(err, "Error while apply rate limit for '%s'", key) - ext.LogError(span2, err2) - resp.Responses[i] = &RateLimitResp{Error: err2.Error()} + err = errors.Wrapf(err, "Error while apply rate limit for '%s'", key) + span.RecordError(err) + resp.Responses[i] = &RateLimitResp{Error: err.Error()} } } else { if HasBehavior(req.Behavior, Behavior_GLOBAL) { - resp.Responses[i], err = s.getGlobalRateLimit(ctx2, req) + resp.Responses[i], err = s.getGlobalRateLimit(ctx, req) if err != nil { - err2 := errors.Wrap(err, "Error in getGlobalRateLimit") - ext.LogError(span2, err2) - resp.Responses[i] = &RateLimitResp{Error: err2.Error()} + err = errors.Wrap(err, "Error in getGlobalRateLimit") + span.RecordError(err) + resp.Responses[i] = &RateLimitResp{Error: err.Error()} } // Inform the client of the owner key of the key resp.Responses[i].Metadata = map[string]string{"owner": peer.Info().GRPCAddress} - return + return nil } // Request must be forwarded to peer that owns the key. // Launch remote peer request in goroutine. wg.Add(1) - go s.asyncRequests(ctx2, &AsyncReq{ + go s.asyncRequests(ctx, &AsyncReq{ AsyncCh: asyncCh, Peer: peer, Req: req, @@ -292,13 +300,15 @@ func (s *V1Instance) GetRateLimits(ctx context.Context, r *GetRateLimitsReq) (*G Idx: i, }) } - }() + + return nil + }) } // Wait for any async responses if any - span3, _ := tracing.StartNamedSpan(ctx, "Wait for responses") + ctxWait := tracing.StartNamedScope(ctx, "Wait for responses") wg.Wait() - span3.Finish() + tracing.EndScope(ctxWait, nil) close(asyncCh) for a := range asyncCh { @@ -326,13 +336,16 @@ func (s *V1Instance) asyncRequests(ctx context.Context, req *AsyncReq) { var attempts int var err error - span, ctx := tracing.StartSpan(ctx) - defer span.Finish() - span.SetTag("request.name", req.Req.Name) - span.SetTag("request.key", req.Req.UniqueKey) - span.SetTag("request.limit", req.Req.Limit) - span.SetTag("request.duration", req.Req.Duration) - span.SetTag("peer.grpcAddress", req.Peer.Info().GRPCAddress) + ctx = tracing.StartScope(ctx) + defer tracing.EndScope(ctx, nil) + span := trace.SpanFromContext(ctx) + span.SetAttributes( + attribute.String("request.name", req.Req.Name), + attribute.String("request.key", req.Req.UniqueKey), + attribute.Int64("request.limit", req.Req.Limit), + attribute.Int64("request.duration", req.Req.Duration), + attribute.String("peer.grpcAddress", req.Peer.Info().GRPCAddress), + ) funcTimer := prometheus.NewTimer(funcTimeMetric.WithLabelValues("V1Instance.asyncRequests")) defer funcTimer.ObserveDuration() @@ -343,14 +356,13 @@ func (s *V1Instance) asyncRequests(ctx context.Context, req *AsyncReq) { for { if attempts > 5 { - logrus. + logrus.WithContext(ctx). WithError(err). WithField("key", req.Key). Error("GetPeer() returned peer that is not connected") - err2 := errors.Wrapf(err, "GetPeer() keeps returning peers that are not connected for '%s'", req.Key) - resp.Resp = &RateLimitResp{Error: err2.Error()} countError(err, "Peer not connected") - ext.LogError(span, err2) + err = errors.Wrapf(err, "GetPeer() keeps returning peers that are not connected for '%s'", req.Key) + resp.Resp = &RateLimitResp{Error: err.Error()} break } @@ -360,13 +372,12 @@ func (s *V1Instance) asyncRequests(ctx context.Context, req *AsyncReq) { getRateLimitCounter.WithLabelValues("local").Add(1) resp.Resp, err = s.getRateLimit(ctx, req.Req) if err != nil { - logrus. + logrus.WithContext(ctx). WithError(err). WithField("key", req.Key). Error("Error applying rate limit") - err2 := errors.Wrapf(err, "Error in getRateLimit for '%s'", req.Key) - resp.Resp = &RateLimitResp{Error: err2.Error()} - ext.LogError(span, err2) + err = errors.Wrapf(err, "Error in getRateLimit for '%s'", req.Key) + resp.Resp = &RateLimitResp{Error: err.Error()} } break } @@ -382,29 +393,26 @@ func (s *V1Instance) asyncRequests(ctx context.Context, req *AsyncReq) { req.Peer, err = s.GetPeer(ctx, req.Key) if err != nil { errPart := fmt.Sprintf("Error finding peer that owns rate limit '%s'", req.Key) - err2 := errors.Wrap(err, errPart) - logrus. + logrus.WithContext(ctx). WithError(err). WithField("key", req.Key). Error(errPart) countError(err, "Error in GetPeer") - ext.LogError(span, err2) - resp.Resp = &RateLimitResp{Error: err2.Error()} + err = errors.Wrap(err, errPart) + resp.Resp = &RateLimitResp{Error: err.Error()} break } continue } - errPart := fmt.Sprintf("Error while fetching rate limit '%s' from peer", req.Key) - err2 := errors.Wrap(err, errPart) - logrus. + logrus.WithContext(ctx). WithError(err). WithField("key", req.Key). Error("Error fetching rate limit from peer") // Not calling `countError()` because we expect the remote end to // report this error. - ext.LogError(span, err2) - resp.Resp = &RateLimitResp{Error: err2.Error()} + err = errors.Wrap(err, fmt.Sprintf("Error while fetching rate limit '%s' from peer", req.Key)) + resp.Resp = &RateLimitResp{Error: err.Error()} break } @@ -424,9 +432,11 @@ func (s *V1Instance) asyncRequests(ctx context.Context, req *AsyncReq) { // getGlobalRateLimit handles rate limits that are marked as `Behavior = GLOBAL`. Rate limit responses // are returned from the local cache and the hits are queued to be sent to the owning peer. -func (s *V1Instance) getGlobalRateLimit(ctx context.Context, req *RateLimitReq) (*RateLimitResp, error) { - span, ctx := tracing.StartSpan(ctx) - defer span.Finish() +func (s *V1Instance) getGlobalRateLimit(ctx context.Context, req *RateLimitReq) (retval *RateLimitResp, reterr error) { + ctx = tracing.StartScope(ctx) + defer func() { + tracing.EndScope(ctx, reterr) + }() funcTimer := prometheus.NewTimer(funcTimeMetric.WithLabelValues("V1Instance.getGlobalRateLimit")) defer funcTimer.ObserveDuration() @@ -439,9 +449,7 @@ func (s *V1Instance) getGlobalRateLimit(ctx context.Context, req *RateLimitReq) item, ok, err := s.gubernatorPool.GetCacheItem(ctx, req.HashKey()) if err != nil { countError(err, "Error in gubernatorPool.GetCacheItem") - err2 := errors.Wrap(err, "Error in checkHandlerPool.GetCacheItem") - ext.LogError(span, err2) - return nil, err2 + return nil, errors.Wrap(err, "Error in checkHandlerPool.GetCacheItem") } if ok { // Global rate limits are always stored as RateLimitResp regardless of algorithm @@ -460,9 +468,7 @@ func (s *V1Instance) getGlobalRateLimit(ctx context.Context, req *RateLimitReq) getRateLimitCounter.WithLabelValues("global").Add(1) resp, err := s.getRateLimit(ctx, cpy) if err != nil { - err2 := errors.Wrap(err, "Error in getRateLimit") - ext.LogError(span, err2) - return nil, err2 + return nil, errors.Wrap(err, "Error in getRateLimit") } return resp, nil @@ -470,9 +476,11 @@ func (s *V1Instance) getGlobalRateLimit(ctx context.Context, req *RateLimitReq) // UpdatePeerGlobals updates the local cache with a list of global rate limits. This method should only // be called by a peer who is the owner of a global rate limit. -func (s *V1Instance) UpdatePeerGlobals(ctx context.Context, r *UpdatePeerGlobalsReq) (*UpdatePeerGlobalsResp, error) { - span, ctx := tracing.StartSpan(ctx) - defer span.Finish() +func (s *V1Instance) UpdatePeerGlobals(ctx context.Context, r *UpdatePeerGlobalsReq) (retval *UpdatePeerGlobalsResp, reterr error) { + ctx = tracing.StartScope(ctx) + defer func() { + tracing.EndScope(ctx, reterr) + }() for _, g := range r.Globals { item := &CacheItem{ @@ -491,17 +499,18 @@ func (s *V1Instance) UpdatePeerGlobals(ctx context.Context, r *UpdatePeerGlobals } // GetPeerRateLimits is called by other peers to get the rate limits owned by this peer. -func (s *V1Instance) GetPeerRateLimits(ctx context.Context, r *GetPeerRateLimitsReq) (*GetPeerRateLimitsResp, error) { - span, ctx := tracing.StartSpan(ctx) - defer span.Finish() - - span.SetTag("numRequests", len(r.Requests)) +func (s *V1Instance) GetPeerRateLimits(ctx context.Context, r *GetPeerRateLimitsReq) (retval *GetPeerRateLimitsResp, reterr error) { + ctx = tracing.StartScope(ctx) + defer func() { + tracing.EndScope(ctx, reterr) + }() + span := trace.SpanFromContext(ctx) + span.SetAttributes(attribute.Int("numRequests", len(r.Requests))) if len(r.Requests) > maxBatchSize { - err2 := fmt.Errorf("'PeerRequest.rate_limits' list too large; max size is '%d'", maxBatchSize) - ext.LogError(span, err2) + err := fmt.Errorf("'PeerRequest.rate_limits' list too large; max size is '%d'", maxBatchSize) checkErrorCounter.WithLabelValues("Request too large").Add(1) - return nil, status.Error(codes.OutOfRange, err2.Error()) + return nil, status.Error(codes.OutOfRange, err.Error()) } // Invoke each rate limit request. @@ -539,9 +548,9 @@ func (s *V1Instance) GetPeerRateLimits(ctx context.Context, r *GetPeerRateLimits rl, err := s.getRateLimit(ctx, rin.req) if err != nil { // Return the error for this request - err2 := errors.Wrap(err, "Error in getRateLimit") - ext.LogError(span, err2) - rl = &RateLimitResp{Error: err2.Error()} + err = errors.Wrap(err, "Error in getRateLimit") + span.RecordError(err) + rl = &RateLimitResp{Error: err.Error()} // checkErrorCounter is updated within getRateLimit(). } @@ -559,15 +568,18 @@ func (s *V1Instance) GetPeerRateLimits(ctx context.Context, r *GetPeerRateLimits } // HealthCheck Returns the health of our instance. -func (s *V1Instance) HealthCheck(ctx context.Context, r *HealthCheckReq) (*HealthCheckResp, error) { - span, ctx := tracing.StartSpan(ctx) - defer span.Finish() +func (s *V1Instance) HealthCheck(ctx context.Context, r *HealthCheckReq) (retval *HealthCheckResp, reterr error) { + ctx = tracing.StartScope(ctx) + defer func() { + tracing.EndScope(ctx, reterr) + }() + span := trace.SpanFromContext(ctx) var errs []string s.peerMutex.RLock() defer s.peerMutex.RUnlock() - tracing.LogInfo(span, "peerMutex.RLock()") + span.AddEvent("peerMutex.RLock()") // Iterate through local peers and get their last errors localPeers := s.conf.LocalPicker.Peers() @@ -575,10 +587,10 @@ func (s *V1Instance) HealthCheck(ctx context.Context, r *HealthCheckReq) (*Healt lastErr := peer.GetLastErr() if lastErr != nil { - for _, err := range lastErr { - err2 := fmt.Errorf("Error returned from local peer.GetLastErr: %s", err) - ext.LogError(span, err2) - errs = append(errs, err2.Error()) + for _, errMsg := range lastErr { + err := fmt.Errorf("Error returned from local peer.GetLastErr: %s", errMsg) + span.RecordError(err) + errs = append(errs, err.Error()) } } } @@ -589,10 +601,10 @@ func (s *V1Instance) HealthCheck(ctx context.Context, r *HealthCheckReq) (*Healt lastErr := peer.GetLastErr() if lastErr != nil { - for _, err := range lastErr { - err2 := fmt.Errorf("Error returned from region peer.GetLastErr: %s", err) - ext.LogError(span, err2) - errs = append(errs, err2.Error()) + for _, errMsg := range lastErr { + err := fmt.Errorf("Error returned from region peer.GetLastErr: %s", errMsg) + span.RecordError(err) + errs = append(errs, err.Error()) } } } @@ -607,19 +619,26 @@ func (s *V1Instance) HealthCheck(ctx context.Context, r *HealthCheckReq) (*Healt health.Message = strings.Join(errs, "|") } - span.SetTag("health.peerCount", health.PeerCount) - span.SetTag("health.status", health.Status) + span.SetAttributes( + attribute.Int64("health.peerCount", int64(health.PeerCount)), + attribute.String("health.status", health.Status), + ) return &health, nil } -func (s *V1Instance) getRateLimit(ctx context.Context, r *RateLimitReq) (*RateLimitResp, error) { - span, ctx := tracing.StartSpan(ctx) - defer span.Finish() - span.SetTag("request.name", r.Name) - span.SetTag("request.key", r.UniqueKey) - span.SetTag("request.limit", r.Limit) - span.SetTag("request.duration", r.Duration) +func (s *V1Instance) getRateLimit(ctx context.Context, r *RateLimitReq) (retval *RateLimitResp, reterr error) { + ctx = tracing.StartScope(ctx) + defer func() { + tracing.EndScope(ctx, reterr) + }() + span := trace.SpanFromContext(ctx) + span.SetAttributes( + attribute.String("request.name", r.Name), + attribute.String("request.key", r.UniqueKey), + attribute.Int64("request.limit", r.Limit), + attribute.Int64("request.duration", r.Duration), + ) funcTimer := prometheus.NewTimer(funcTimeMetric.WithLabelValues("V1Instance.getRateLimit")) defer funcTimer.ObserveDuration() @@ -627,12 +646,12 @@ func (s *V1Instance) getRateLimit(ctx context.Context, r *RateLimitReq) (*RateLi if HasBehavior(r.Behavior, Behavior_GLOBAL) { s.global.QueueUpdate(r) - tracing.LogInfo(span, "s.global.QueueUpdate(r)") + span.AddEvent("s.global.QueueUpdate(r)") } if HasBehavior(r.Behavior, Behavior_MULTI_REGION) { s.mutliRegion.QueueHits(r) - tracing.LogInfo(span, "s.mutliRegion.QueueHits(r)") + span.AddEvent("s.mutliRegion.QueueHits(r)") } resp, err := s.gubernatorPool.GetRateLimit(ctx, r) @@ -687,7 +706,7 @@ func (s *V1Instance) SetPeers(peerInfo []PeerInfo) { s.log.WithField("peers", peerInfo).Debug("peers updated") // Shutdown any old peers we no longer need - ctx, cancel := tracing.ContextWithTimeout(context.Background(), s.conf.Behaviors.BatchTimeout) + ctx, cancel := ctxutil.WithTimeout(context.Background(), s.conf.Behaviors.BatchTimeout) defer cancel() var shutdownPeers []*PeerClient @@ -728,9 +747,12 @@ func (s *V1Instance) SetPeers(peerInfo []PeerInfo) { } // GetPeer returns a peer client for the hash key provided -func (s *V1Instance) GetPeer(ctx context.Context, key string) (*PeerClient, error) { - span, ctx := tracing.StartSpan(ctx) - defer span.Finish() +func (s *V1Instance) GetPeer(ctx context.Context, key string) (retval *PeerClient, reterr error) { + ctx = tracing.StartScope(ctx) + defer func() { + tracing.EndScope(ctx, reterr) + }() + span := trace.SpanFromContext(ctx) funcTimer := prometheus.NewTimer(funcTimeMetric.WithLabelValues("V1Instance.GetPeer")) defer funcTimer.ObserveDuration() @@ -738,14 +760,12 @@ func (s *V1Instance) GetPeer(ctx context.Context, key string) (*PeerClient, erro s.peerMutex.RLock() defer s.peerMutex.RUnlock() - tracing.LogInfo(span, "peerMutex.RLock()") + span.AddEvent("peerMutex.RLock()") lockTimer.ObserveDuration() peer, err := s.conf.LocalPicker.Get(key) if err != nil { - err2 := errors.Wrap(err, "Error in conf.LocalPicker.Get") - ext.LogError(span, err2) - return nil, err2 + return nil, errors.Wrap(err, "Error in conf.LocalPicker.Get") } return peer, nil diff --git a/gubernator_pool.go b/gubernator_pool.go index 2ffe9665..649f8d25 100644 --- a/gubernator_pool.go +++ b/gubernator_pool.go @@ -45,11 +45,12 @@ import ( "sync/atomic" "github.com/OneOfOne/xxhash" - "github.com/mailgun/gubernator/v2/tracing" + "github.com/mailgun/holster/v4/errors" "github.com/mailgun/holster/v4/setter" - "github.com/opentracing/opentracing-go/ext" - "github.com/pkg/errors" + "github.com/mailgun/holster/v4/tracing" "github.com/sirupsen/logrus" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" ) type GubernatorPool struct { @@ -133,7 +134,7 @@ func NewGubernatorPool(conf *Config, concurrency int, cacheSize int) *Gubernator workers: make([]*poolWorker, concurrency), workerCacheSize: cacheSize / concurrency, hasher: newPoolHasher(), - hashRingStep: uint64(1 << 63) / uint64(concurrency), + hashRingStep: uint64(1<<63) / uint64(concurrency), conf: conf, done: make(chan struct{}), } @@ -246,9 +247,12 @@ func (chp *GubernatorPool) worker(worker *poolWorker) { } // Send a GetRateLimit request to worker pool. -func (chp *GubernatorPool) GetRateLimit(ctx context.Context, rlRequest *RateLimitReq) (*RateLimitResp, error) { - span, ctx := tracing.StartSpan(ctx) - defer span.Finish() +func (chp *GubernatorPool) GetRateLimit(ctx context.Context, rlRequest *RateLimitReq) (retval *RateLimitResp, reterr error) { + ctx = tracing.StartScope(ctx) + defer func() { + tracing.EndScope(ctx, reterr) + }() + span := trace.SpanFromContext(ctx) // Delegate request to assigned channel based on request key. worker := chp.getWorker(rlRequest.UniqueKey) @@ -259,33 +263,34 @@ func (chp *GubernatorPool) GetRateLimit(ctx context.Context, rlRequest *RateLimi } // Send request. - tracing.LogInfo(span, "Sending request...", "channelLength", len(worker.getRateLimitRequest)) + span.AddEvent("Sending request...", trace.WithAttributes( + attribute.Int("channelLength", len(worker.getRateLimitRequest)), + )) + select { case worker.getRateLimitRequest <- handlerRequest: // Successfully sent request. case <-ctx.Done(): - ext.LogError(span, ctx.Err()) return nil, ctx.Err() } poolWorkerQueueLength.WithLabelValues("GetRateLimit", worker.name).Observe(float64(len(worker.getRateLimitRequest))) // Wait for response. - tracing.LogInfo(span, "Waiting for response...") + span.AddEvent("Waiting for response...") select { case handlerResponse := <-handlerRequest.resp: // Successfully read response. return handlerResponse.rl, handlerResponse.err case <-ctx.Done(): - ext.LogError(span, ctx.Err()) return nil, ctx.Err() } } // Handle request received by worker. func (chp *GubernatorPool) handleGetRateLimit(handlerRequest *request, cache Cache) { - span, ctx := tracing.StartSpan(handlerRequest.ctx) - defer span.Finish() + ctx := tracing.StartScope(handlerRequest.ctx) + defer tracing.EndScope(ctx, nil) var rlResponse *RateLimitResp var err error @@ -297,7 +302,7 @@ func (chp *GubernatorPool) handleGetRateLimit(handlerRequest *request, cache Cac msg := "Error in tokenBucket" countError(err, msg) err = errors.Wrap(err, msg) - ext.LogError(span, err) + trace.SpanFromContext(ctx).RecordError(err) } case Algorithm_LEAKY_BUCKET: @@ -306,12 +311,12 @@ func (chp *GubernatorPool) handleGetRateLimit(handlerRequest *request, cache Cac msg := "Error in leakyBucket" countError(err, msg) err = errors.Wrap(err, msg) - ext.LogError(span, err) + trace.SpanFromContext(ctx).RecordError(err) } default: err = errors.Errorf("Invalid rate limit algorithm '%d'", handlerRequest.request.Algorithm) - ext.LogError(span, err) + trace.SpanFromContext(ctx).RecordError(err) checkErrorCounter.WithLabelValues("Invalid algorithm").Add(1) } @@ -326,16 +331,18 @@ func (chp *GubernatorPool) handleGetRateLimit(handlerRequest *request, cache Cac case <-ctx.Done(): // Context canceled. - ext.LogError(span, ctx.Err()) + trace.SpanFromContext(ctx).RecordError(err) } } // Atomically load cache from persistent storage. // Read from persistent storage. Load into each appropriate worker's cache. // Workers are locked during this load operation to prevent race conditions. -func (chp *GubernatorPool) Load(ctx context.Context) error { - span, ctx := tracing.StartSpan(ctx) - defer span.Finish() +func (chp *GubernatorPool) Load(ctx context.Context) (reterr error) { + ctx = tracing.StartScope(ctx) + defer func() { + tracing.EndScope(ctx, reterr) + }() ch, err := chp.conf.Loader.Load() if err != nil { @@ -420,8 +427,8 @@ mainloop: } func (chp *GubernatorPool) handleLoad(request poolLoadRequest, cache Cache) { - span, ctx := tracing.StartSpan(request.ctx) - defer span.Finish() + ctx := tracing.StartScope(request.ctx) + defer tracing.EndScope(ctx, nil) mainloop: for { @@ -451,16 +458,18 @@ mainloop: case <-ctx.Done(): // Context canceled. - ext.LogError(span, ctx.Err()) + trace.SpanFromContext(ctx).RecordError(ctx.Err()) } } // Atomically store cache to persistent storage. // Save all workers' caches to persistent storage. // Workers are locked during this store operation to prevent race conditions. -func (chp *GubernatorPool) Store(ctx context.Context) error { - span, ctx := tracing.StartSpan(ctx) - defer span.Finish() +func (chp *GubernatorPool) Store(ctx context.Context) (reterr error) { + ctx = tracing.StartScope(ctx) + defer func() { + tracing.EndScope(ctx, reterr) + }() var wg sync.WaitGroup out := make(chan *CacheItem, 500) @@ -469,14 +478,14 @@ func (chp *GubernatorPool) Store(ctx context.Context) error { for _, worker := range chp.workers { wg.Add(1) - go func(worker *poolWorker) { - span2, ctx2 := tracing.StartNamedSpan(ctx, fmt.Sprintf("%p", worker)) - defer span2.Finish() + go func(ctx context.Context, worker *poolWorker) { + ctx = tracing.StartNamedScope(ctx, fmt.Sprintf("%p", worker)) + defer tracing.EndScope(ctx, nil) defer wg.Done() respChan := make(chan poolStoreResponse) req := poolStoreRequest{ - ctx: ctx2, + ctx: ctx, response: respChan, out: out, } @@ -489,18 +498,18 @@ func (chp *GubernatorPool) Store(ctx context.Context) error { // Successfully received response. return - case <-ctx2.Done(): + case <-ctx.Done(): // Context canceled. - ext.LogError(span2, ctx2.Err()) + trace.SpanFromContext(ctx).RecordError(ctx.Err()) return } - case <-ctx2.Done(): + case <-ctx.Done(): // Context canceled. - ext.LogError(span2, ctx2.Err()) + trace.SpanFromContext(ctx).RecordError(ctx.Err()) return } - }(worker) + }(ctx, worker) } // When all iterators are done, close `out` channel. @@ -510,16 +519,20 @@ func (chp *GubernatorPool) Store(ctx context.Context) error { }() if ctx.Err() != nil { - ext.LogError(span, ctx.Err()) return ctx.Err() } - return chp.conf.Loader.Save(out) + err := chp.conf.Loader.Save(out) + if err != nil { + return errors.Wrap(err, "error in chp.conf.Loader.Save") + } + + return nil } func (chp *GubernatorPool) handleStore(request poolStoreRequest, cache Cache) { - span, ctx := tracing.StartSpan(request.ctx) - defer span.Finish() + ctx := tracing.StartScope(request.ctx) + defer tracing.EndScope(ctx, nil) for item := range cache.Each() { select { @@ -528,7 +541,7 @@ func (chp *GubernatorPool) handleStore(request poolStoreRequest, cache Cache) { case <-ctx.Done(): // Context canceled. - ext.LogError(span, ctx.Err()) + trace.SpanFromContext(ctx).RecordError(ctx.Err()) return } } @@ -541,14 +554,16 @@ func (chp *GubernatorPool) handleStore(request poolStoreRequest, cache Cache) { case <-ctx.Done(): // Context canceled. - ext.LogError(span, ctx.Err()) + trace.SpanFromContext(ctx).RecordError(ctx.Err()) } } // Add to worker's cache. -func (chp *GubernatorPool) AddCacheItem(ctx context.Context, key string, item *CacheItem) error { - span, ctx := tracing.StartSpan(ctx) - defer span.Finish() +func (chp *GubernatorPool) AddCacheItem(ctx context.Context, key string, item *CacheItem) (reterr error) { + ctx = tracing.StartScope(ctx) + defer func() { + tracing.EndScope(ctx, reterr) + }() respChan := make(chan poolAddCacheItemResponse) worker := chp.getWorker(key) @@ -570,20 +585,18 @@ func (chp *GubernatorPool) AddCacheItem(ctx context.Context, key string, item *C case <-ctx.Done(): // Context canceled. - ext.LogError(span, ctx.Err()) return ctx.Err() } case <-ctx.Done(): // Context canceled. - ext.LogError(span, ctx.Err()) return ctx.Err() } } func (chp *GubernatorPool) handleAddCacheItem(request poolAddCacheItemRequest, cache Cache) { - span, ctx := tracing.StartSpan(request.ctx) - defer span.Finish() + ctx := tracing.StartScope(request.ctx) + defer tracing.EndScope(ctx, nil) exists := cache.Add(request.item) response := poolAddCacheItemResponse{exists} @@ -594,14 +607,16 @@ func (chp *GubernatorPool) handleAddCacheItem(request poolAddCacheItemRequest, c case <-ctx.Done(): // Context canceled. - ext.LogError(span, ctx.Err()) + trace.SpanFromContext(ctx).RecordError(ctx.Err()) } } // Get item from worker's cache. -func (chp *GubernatorPool) GetCacheItem(ctx context.Context, key string) (*CacheItem, bool, error) { - span, ctx := tracing.StartSpan(ctx) - defer span.Finish() +func (chp *GubernatorPool) GetCacheItem(ctx context.Context, key string) (item *CacheItem, found bool, reterr error) { + ctx = tracing.StartScope(ctx) + defer func() { + tracing.EndScope(ctx, reterr) + }() respChan := make(chan poolGetCacheItemResponse) worker := chp.getWorker(key) @@ -623,20 +638,18 @@ func (chp *GubernatorPool) GetCacheItem(ctx context.Context, key string) (*Cache case <-ctx.Done(): // Context canceled. - ext.LogError(span, ctx.Err()) return nil, false, ctx.Err() } case <-ctx.Done(): // Context canceled. - ext.LogError(span, ctx.Err()) return nil, false, ctx.Err() } } func (chp *GubernatorPool) handleGetCacheItem(request poolGetCacheItemRequest, cache Cache) { - span, ctx := tracing.StartSpan(request.ctx) - defer span.Finish() + ctx := tracing.StartScope(request.ctx) + defer tracing.EndScope(ctx, nil) item, ok := cache.GetItem(request.key) response := poolGetCacheItemResponse{item, ok} @@ -647,6 +660,6 @@ func (chp *GubernatorPool) handleGetCacheItem(request poolGetCacheItemRequest, c case <-ctx.Done(): // Context canceled. - ext.LogError(span, ctx.Err()) + trace.SpanFromContext(ctx).RecordError(ctx.Err()) } } diff --git a/gubernator_pool_internal_test.go b/gubernator_pool_internal_test.go index dfa2cd49..ad364cb5 100644 --- a/gubernator_pool_internal_test.go +++ b/gubernator_pool_internal_test.go @@ -42,9 +42,9 @@ func TestGubernatorPoolInternal(t *testing.T) { conf.SetDefaults() // Test that getWorker() interpolates the hash to find the expected worker. - testCases := []struct{ - Name string - Hash uint64 + testCases := []struct { + Name string + Hash uint64 ExpectedIdx int }{ {"Hash 0%", 0, 0}, diff --git a/jaegertracing.md b/jaegertracing.md index 7b67f60e..eaf32069 100644 --- a/jaegertracing.md +++ b/jaegertracing.md @@ -1,76 +1,97 @@ -# Jaeger Tracing -Gubernator supports [OpenTracing](https://opentracing.io) for generating -detailed traces of server behavior using [Jaeger -Tracing](https://www.jaegertracing.io/) tools. +# OpenTelemetry Tracing with Jaeger +Gubernator supports [OpenTelemetry](https://opentelemetry.io) for generating +detailed traces of application behavior and sending to [Jaeger +Tracing](https://www.jaegertracing.io/) server. -## Enabling Jaeger -Jaeger is enabled by default and sends traces to localhost port 6831/udp. +Read more at: +[https://github.com/mailgun/holster/blob/master/tracing/README.md](https://github.com/mailgun/holster/blob/master/tracing/README.md) -Configure with environment variables, such as: +## Enabling Jaeger Exporter +Jaeger export is enabled by default and sends traces to localhost port +6831/udp. -| Name | Description | -| ---------------------- | ----------- | -| `JAEGER_SERVICE_NAME` | Service name. | -| `JAEGER_AGENT_HOST` | Jaeger server hostname or IP. | -| `JAEGER_SAMPLER_TYPE` | The sampler type: `remote`, `const`, `probablistic`, or `ratelimiting`. | -| `JAEGER_SAMPLER_PARAM` | The sampler parameter. | -| `JAEGER_DISABLED` | Set to `true` to disable sending Jaeger traces. | - -See also the [full list of variables](https://github.com/jaegertracing/jaeger-client-go#environment-variables). +Configure with environment variables. See [OpenTelemetry configuration +spec](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md). ## Sampling -Because Gubernator generates a trace for each request, it is recommended to use -`probablistic` or `ratelimiting` [sampler -type](https://www.jaegertracing.io/docs/1.30/sampling/) to reduce the volume of -data sent to your Jaeger server. +Because Gubernator generates a trace for each request, the tracing volume could +exceed Jaeger's resources. In production, it is recommended to set +`OTEL_TRACES_SAMPLER=parentbased_traceidratio` [sampler +type](https://opentelemetry.io/docs/concepts/sdk-configuration/general-sdk-configuration/#otel_traces_sampler) and +`OTEL_TRACES_SAMPLER_ARG` to a decimal number between 0 (none) and 1 (all) for +the proportion of traces to be sampled. ## Distributed Traces -OpenTracing defines capabilities for clients to send trace ids to downstream +OpenTelemetry defines capabilities for clients to send trace ids to downstream services. That service will link the client span with the server span. When the client and server both send traces to the same Jaeger server, the trace will appear with the two spans linked in the same view. -See `tracing/tracing.go` for usage examples. +When sending gRPC requests to Gubernator, be sure to use the [`otelgrpc` +interceptor](https://github.com/open-telemetry/opentelemetry-go-contrib) to +propagate the client's trace context to the server so it can add spans. -### Gubernator Standlone -When deployed as a standalone daemon, Gubernator's gRPC service will receive -embedded trace ids in requests from the client's `context` object. +See [gRPC](#gRPC) section and `cmd/gubernator-cli/main.go` for usage examples. -For this to work, the client must be configured to embed tracing ids. +## Exporting to Remote Jaeger Server +Normally, Jaeger all-in-one or a Jaeger Agent is running locally on the server +and listening to port 6831/udp. Gubernator would talk to Jaeger by exporting +traces to localhost port 6831/udp. + +However, in situations where Jaeger cannot be made accessable via localhost, it +is recommended to export traces via HTTP using this configuration: + +``` +OTEL_EXPORTER_JAEGER_PROTOCOL=http/thrift.binary +OTEL_EXPORTER_JAEGER_ENDPOINT=http://:14268/api/traces +``` -#### gRPC +**Why not set `OTEL_EXPORTER_JAEGER_AGENT_HOST`?** +This setting works by exporting UDP datagrams to the remote host, instead of +localhost. This will work, but runs the risk of data loss. If a span is +exported with sufficient data, it will exceed the network interface's MTU size +and the datagram will be dropped. This is only a problem when sending to a +remote host. The loopback interface MTU is typically much larger and doesn't +encounter this problem. + +When exporting via HTTP there is no MTU limit. This effectively bypasses the +Jaeger Agent and sends directly to Jaeger's collector. + +## gRPC If using Gubernator's Golang gRPC client, the client must be created like so: ```go import ( - "github.com/opentracing/opentracing-go" - otgrpc "github.com/opentracing-contrib/go-grpc" + "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" "google.golang.org/grpc" ) // ... - tracer := opentracing.GlobalTracer() - tracingUnaryInterceptor := otgrpc.OpenTracingClientInterceptor(tracer) - tracingStreamInterceptor := otgrpc.OpenTracingStreamClientInterceptor(tracer) - opts := []grpc.DialOption{ grpc.WithBlock(), - grpc.WithUnaryInterceptor(tracingUnaryInterceptor), - grpc.WithStreamInterceptor(tracingStreamInterceptor), + grpc.WithUnaryInterceptor(otelgrpc.UnaryClientInterceptor()), + grpc.WithStreamInterceptor(otelgrpc.StreamClientInterceptor()), } - endpoint := "" + endpoint := "" conn, err := grpc.DialContext(ctx, endpoint, opts...) ``` -#### HTTP -If using HTTP, the tracing ids must be embedded in HTTP headers. This is -typically done using Jaeger client functionality. +## HTTP +If using HTTP, the tracing ids must be propagated in HTTP headers. This is +typically done using OpenTelemetry instrumentation, such as [`otelhttp`](https://pkg.go.dev/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp). + +See [OpenTelemetry registry](https://opentelemetry.io/registry/?language=go) +for instrumentation using many other HTTP frameworks. -See: https://medium.com/opentracing/distributed-tracing-in-10-minutes-51b378ee40f1 +## Gubernator Standlone +When deployed as a standalone daemon, Gubernator's gRPC service will receive +embedded trace ids in requests from the client's `context` object. + +For this to work, the client must be configured to embed tracing ids. -### Gubernator Module +## Gubernator Module When embedded into a dependent codebase as a Go module, most all Gubernator functions create spans linked to the trace ids embedded into the `context` object. diff --git a/peer_client.go b/peer_client.go index 940dbade..df700e83 100644 --- a/peer_client.go +++ b/peer_client.go @@ -22,15 +22,16 @@ import ( "fmt" "sync" - "github.com/mailgun/gubernator/v2/tracing" "github.com/mailgun/holster/v4/clock" "github.com/mailgun/holster/v4/collections" - otgrpc "github.com/opentracing-contrib/go-grpc" - "github.com/opentracing/opentracing-go" - "github.com/opentracing/opentracing-go/ext" - "github.com/pkg/errors" + "github.com/mailgun/holster/v4/ctxutil" + "github.com/mailgun/holster/v4/errors" + "github.com/mailgun/holster/v4/tracing" "github.com/prometheus/client_golang/prometheus" "github.com/sirupsen/logrus" + "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" "google.golang.org/grpc" "google.golang.org/grpc/credentials" ) @@ -91,9 +92,12 @@ func NewPeerClient(conf PeerConfig) *PeerClient { } // Connect establishes a GRPC connection to a peer -func (c *PeerClient) connect(ctx context.Context) error { - span, ctx := tracing.StartSpan(ctx) - defer span.Finish() +func (c *PeerClient) connect(ctx context.Context) (reterr error) { + ctx = tracing.StartScope(ctx) + defer func() { + tracing.EndScope(ctx, reterr) + }() + span := trace.SpanFromContext(ctx) // NOTE: To future self, this mutex is used here because we need to know if the peer is disconnecting and // handle ErrClosing. Since this mutex MUST be here we take this opportunity to also see if we are connected. @@ -107,7 +111,7 @@ func (c *PeerClient) connect(ctx context.Context) error { c.mutex.RLock() lockTimer.ObserveDuration() - tracing.LogInfo(span, "mutex.RLock()") + span.AddEvent("mutex.RLock()") if c.status == peerClosing { c.mutex.RUnlock() @@ -123,22 +127,17 @@ func (c *PeerClient) connect(ctx context.Context) error { c.mutex.RUnlock() c.mutex.Lock() defer c.mutex.Unlock() - tracing.LogInfo(span, "mutex.Lock()") + span.AddEvent("mutex.Lock()") // Now that we have the RW lock, ensure no else got here ahead of us. if c.status == peerConnected { return nil } - // Setup Opentracing interceptor to propagate spans. - tracer := opentracing.GlobalTracer() - tracingUnaryInterceptor := otgrpc.OpenTracingClientInterceptor(tracer) - tracingStreamInterceptor := otgrpc.OpenTracingStreamClientInterceptor(tracer) - - var err error + // Setup OpenTelemetry interceptor to propagate spans. opts := []grpc.DialOption{ - grpc.WithUnaryInterceptor(tracingUnaryInterceptor), - grpc.WithStreamInterceptor(tracingStreamInterceptor), + grpc.WithUnaryInterceptor(otelgrpc.UnaryClientInterceptor()), + grpc.WithStreamInterceptor(otelgrpc.StreamClientInterceptor()), } if c.conf.TLS != nil { @@ -147,6 +146,7 @@ func (c *PeerClient) connect(ctx context.Context) error { opts = append(opts, grpc.WithInsecure()) } + var err error c.conn, err = grpc.Dial(c.conf.Info.GRPCAddress, opts...) if err != nil { return c.setLastErr(&PeerErr{err: errors.Wrapf(err, "failed to dial peer %s", c.conf.Info.GRPCAddress)}) @@ -167,13 +167,18 @@ func (c *PeerClient) Info() PeerInfo { // GetPeerRateLimit forwards a rate limit request to a peer. If the rate limit has `behavior == BATCHING` configured // this method will attempt to batch the rate limits -func (c *PeerClient) GetPeerRateLimit(ctx context.Context, r *RateLimitReq) (*RateLimitResp, error) { - span, ctx := tracing.StartSpan(ctx) - defer span.Finish() - span.SetTag("request.name", r.Name) - span.SetTag("request.key", r.UniqueKey) - span.SetTag("request.limit", r.Limit) - span.SetTag("request.duration", r.Duration) +func (c *PeerClient) GetPeerRateLimit(ctx context.Context, r *RateLimitReq) (retval *RateLimitResp, reterr error) { + ctx = tracing.StartScope(ctx) + defer func() { + tracing.EndScope(ctx, reterr) + }() + span := trace.SpanFromContext(ctx) + span.SetAttributes( + attribute.String("request.name", r.Name), + attribute.String("request.key", r.UniqueKey), + attribute.Int64("request.limit", r.Limit), + attribute.Int64("request.duration", r.Duration), + ) // If config asked for no batching if HasBehavior(r.Behavior, Behavior_NO_BATCHING) { @@ -182,41 +187,41 @@ func (c *PeerClient) GetPeerRateLimit(ctx context.Context, r *RateLimitReq) (*Ra Requests: []*RateLimitReq{r}, }) if err != nil { - err2 := errors.Wrap(err, "Error in GetPeerRateLimits") - ext.LogError(span, err2) - return nil, c.setLastErr(err2) + err = errors.Wrap(err, "Error in GetPeerRateLimits") + return nil, c.setLastErr(err) } return resp.RateLimits[0], nil } rateLimitResp, err := c.getPeerRateLimitsBatch(ctx, r) if err != nil { - err2 := errors.Wrap(err, "Error in getPeerRateLimitsBatch") - ext.LogError(span, err2) - return nil, c.setLastErr(err2) + err = errors.Wrap(err, "Error in getPeerRateLimitsBatch") + return nil, c.setLastErr(err) } return rateLimitResp, nil } // GetPeerRateLimits requests a list of rate limit statuses from a peer -func (c *PeerClient) GetPeerRateLimits(ctx context.Context, r *GetPeerRateLimitsReq) (*GetPeerRateLimitsResp, error) { - span, ctx := tracing.StartSpan(ctx) - defer span.Finish() - span.SetTag("numRequests", len(r.Requests)) +func (c *PeerClient) GetPeerRateLimits(ctx context.Context, r *GetPeerRateLimitsReq) (retval *GetPeerRateLimitsResp, reterr error) { + ctx = tracing.StartScope(ctx) + defer func() { + tracing.EndScope(ctx, reterr) + }() + span := trace.SpanFromContext(ctx) + span.SetAttributes(attribute.Int("numRequests", len(r.Requests))) if err := c.connect(ctx); err != nil { - err2 := errors.Wrap(err, "Error in connect") - ext.LogError(span, err2) + err = errors.Wrap(err, "Error in connect") checkErrorCounter.WithLabelValues("Connect error").Add(1) - return nil, c.setLastErr(err2) + return nil, c.setLastErr(err) } // NOTE: This must be done within the RLock since calling Wait() in Shutdown() causes // a race condition if called within a separate go routine if the internal wg is `0` // when Wait() is called then Add(1) is called concurrently. c.mutex.RLock() - tracing.LogInfo(span, "mutex.RLock()") + span.AddEvent("mutex.RLock()") c.wg.Add(1) defer func() { c.mutex.RUnlock() @@ -225,16 +230,14 @@ func (c *PeerClient) GetPeerRateLimits(ctx context.Context, r *GetPeerRateLimits resp, err := c.client.GetPeerRateLimits(ctx, r) if err != nil { - err2 := errors.Wrap(err, "Error in client.GetPeerRateLimits") - ext.LogError(span, err2) + err = errors.Wrap(err, "Error in client.GetPeerRateLimits") // checkErrorCounter is updated within client.GetPeerRateLimits(). - return nil, c.setLastErr(err2) + return nil, c.setLastErr(err) } // Unlikely, but this avoids a panic if something wonky happens if len(resp.RateLimits) != len(r.Requests) { err = errors.New("number of rate limits in peer response does not match request") - ext.LogError(span, err) checkErrorCounter.WithLabelValues("Item mismatch").Add(1) return nil, c.setLastErr(err) } @@ -242,9 +245,12 @@ func (c *PeerClient) GetPeerRateLimits(ctx context.Context, r *GetPeerRateLimits } // UpdatePeerGlobals sends global rate limit status updates to a peer -func (c *PeerClient) UpdatePeerGlobals(ctx context.Context, r *UpdatePeerGlobalsReq) (*UpdatePeerGlobalsResp, error) { - span, ctx := tracing.StartSpan(ctx) - defer span.Finish() +func (c *PeerClient) UpdatePeerGlobals(ctx context.Context, r *UpdatePeerGlobalsReq) (retval *UpdatePeerGlobalsResp, reterr error) { + ctx = tracing.StartScope(ctx) + defer func() { + tracing.EndScope(ctx, reterr) + }() + span := trace.SpanFromContext(ctx) if err := c.connect(ctx); err != nil { return nil, c.setLastErr(err) @@ -252,7 +258,7 @@ func (c *PeerClient) UpdatePeerGlobals(ctx context.Context, r *UpdatePeerGlobals // See NOTE above about RLock and wg.Add(1) c.mutex.RLock() - tracing.LogInfo(span, "mutex.RLock()") + span.AddEvent("mutex.RLock()") c.wg.Add(1) defer func() { c.mutex.RUnlock() @@ -298,30 +304,33 @@ func (c *PeerClient) GetLastErr() []string { return errs } -func (c *PeerClient) getPeerRateLimitsBatch(ctx context.Context, r *RateLimitReq) (*RateLimitResp, error) { - span, ctx := tracing.StartSpan(ctx) - defer span.Finish() - span.SetTag("request.name", r.Name) - span.SetTag("request.key", r.UniqueKey) - span.SetTag("request.limit", r.Limit) - span.SetTag("request.duration", r.Duration) +func (c *PeerClient) getPeerRateLimitsBatch(ctx context.Context, r *RateLimitReq) (retval *RateLimitResp, reterr error) { + ctx = tracing.StartScope(ctx) + defer func() { + tracing.EndScope(ctx, reterr) + }() + span := trace.SpanFromContext(ctx) + span.SetAttributes( + attribute.String("request.name", r.Name), + attribute.String("request.key", r.UniqueKey), + attribute.Int64("request.limit", r.Limit), + attribute.Int64("request.duration", r.Duration), + ) funcTimer := prometheus.NewTimer(funcTimeMetric.WithLabelValues("PeerClient.getPeerRateLimitsBatch")) defer funcTimer.ObserveDuration() if err := c.connect(ctx); err != nil { - err2 := errors.Wrap(err, "Error in connect") - ext.LogError(span, err2) - return nil, c.setLastErr(err2) + err = errors.Wrap(err, "Error in connect") + return nil, c.setLastErr(err) } // See NOTE above about RLock and wg.Add(1) c.mutex.RLock() - tracing.LogInfo(span, "mutex.RLock()") + span.AddEvent("mutex.RLock()") if c.status == peerClosing { - err2 := &PeerErr{err: errors.New("already disconnecting")} - ext.LogError(span, err2) - return nil, c.setLastErr(err2) + err := &PeerErr{err: errors.New("already disconnecting")} + return nil, c.setLastErr(err) } req := request{ request: r, @@ -330,7 +339,9 @@ func (c *PeerClient) getPeerRateLimitsBatch(ctx context.Context, r *RateLimitReq } // Enqueue the request to be sent - tracing.LogInfo(span, "Enqueue request", "queueLength", len(c.queue)) + span.AddEvent("Enqueue request", trace.WithAttributes( + attribute.Int("queueLength", len(c.queue)), + )) peerAddr := c.Info().GRPCAddress queueLengthMetric.WithLabelValues(peerAddr).Observe(float64(len(c.queue))) @@ -338,9 +349,7 @@ func (c *PeerClient) getPeerRateLimitsBatch(ctx context.Context, r *RateLimitReq case c.queue <- &req: // Successfully enqueued request. case <-ctx.Done(): - err := errors.Wrap(ctx.Err(), "Error while enqueuing request") - ext.LogError(span, err) - return nil, err + return nil, errors.Wrap(ctx.Err(), "Error while enqueuing request") } c.wg.Add(1) @@ -350,21 +359,18 @@ func (c *PeerClient) getPeerRateLimitsBatch(ctx context.Context, r *RateLimitReq }() // Wait for a response or context cancel - span3, ctx2 := tracing.StartNamedSpan(ctx, "Wait for response") - defer span3.Finish() + ctx2 := tracing.StartNamedScope(ctx, "Wait for response") + defer tracing.EndScope(ctx2, nil) select { case resp := <-req.resp: if resp.err != nil { - err2 := errors.Wrap(c.setLastErr(resp.err), "Request error") - ext.LogError(span, err2) - return nil, c.setLastErr(err2) + err := errors.Wrap(c.setLastErr(resp.err), "Request error") + return nil, c.setLastErr(err) } return resp.rl, nil case <-ctx2.Done(): - err := errors.Wrap(ctx2.Err(), "Error while waiting for response") - ext.LogError(span, err) - return nil, err + return nil, errors.Wrap(ctx2.Err(), "Error while waiting for response") } } @@ -389,28 +395,30 @@ func (c *PeerClient) run() { return } - // Wrap logic in anon function so we can use defer. - func() { - // Use context of the request for opentracing span. - flushSpan, _ := tracing.StartNamedSpan(r.ctx, "Enqueue batched request") - defer flushSpan.Finish() - flushSpan.SetTag("peer.grpcAddress", c.conf.Info.GRPCAddress) + _ = tracing.Scope(r.ctx, func(reqCtx context.Context) error { + span := trace.SpanFromContext(reqCtx) + span.SetAttributes( + attribute.String("peer.grpcAddress", c.conf.Info.GRPCAddress), + ) queue = append(queue, r) // Send the queue if we reached our batch limit if len(queue) >= c.conf.Behavior.BatchLimit { - logMsg := "run() reached batch limit" - logrus.WithFields(logrus.Fields{ - "queueLen": len(queue), - "batchLimit": c.conf.Behavior.BatchLimit, - }).Info(logMsg) - tracing.LogInfo(flushSpan, logMsg) - - go c.sendQueue(ctx, queue) + logrus.WithContext(reqCtx). + WithFields(logrus.Fields{ + "queueLen": len(queue), + "batchLimit": c.conf.Behavior.BatchLimit, + }). + Info("run() reached batch limit") + + queue2 := queue queue = nil - interval.Next() - return + go c.sendQueue(ctx, queue2) + + // TODO: The `interval` timer should be reset to abort the + // pending tick that's still scheduled. + return nil } // If this is our first enqueued item since last @@ -418,12 +426,26 @@ func (c *PeerClient) run() { if len(queue) == 1 { interval.Next() } - }() + + return nil + }) case <-interval.C: - if len(queue) != 0 { - go c.sendQueue(ctx, queue) + queue2 := queue + + if len(queue2) > 0 { queue = nil + + go func() { + ctx2 := tracing.StartScope(ctx) + defer tracing.EndScope(ctx2, nil) + intervalSpan := trace.SpanFromContext(ctx2) + intervalSpan.SetAttributes( + attribute.String("batchWait", c.conf.Behavior.BatchWait.String()), + ) + + c.sendQueue(ctx2, queue2) + }() } } } @@ -432,10 +454,13 @@ func (c *PeerClient) run() { // sendQueue sends the queue provided and returns the responses to // waiting go routines func (c *PeerClient) sendQueue(ctx context.Context, queue []*request) { - span, ctx := tracing.StartSpan(ctx) - defer span.Finish() - span.SetTag("queueLen", len(queue)) - span.SetTag("peer.grpcAddress", c.conf.Info.GRPCAddress) + ctx = tracing.StartScope(ctx) + defer tracing.EndScope(ctx, nil) + span := trace.SpanFromContext(ctx) + span.SetAttributes( + attribute.Int("queueLen", len(queue)), + attribute.String("peer.grpcAddress", c.conf.Info.GRPCAddress), + ) batchSendTimer := prometheus.NewTimer(batchSendDurationMetric.WithLabelValues(c.conf.Info.GRPCAddress)) defer batchSendTimer.ObserveDuration() @@ -447,23 +472,22 @@ func (c *PeerClient) sendQueue(ctx context.Context, queue []*request) { req.Requests = append(req.Requests, r.request) } - ctx2, cancel2 := tracing.ContextWithTimeout(ctx, c.conf.Behavior.BatchTimeout) + ctx2, cancel2 := ctxutil.WithTimeout(ctx, c.conf.Behavior.BatchTimeout) resp, err := c.client.GetPeerRateLimits(ctx2, &req) cancel2() // An error here indicates the entire request failed if err != nil { logPart := "Error in client.GetPeerRateLimits" - err2 := errors.Wrap(err, logPart) - logrus. + logrus.WithContext(ctx). WithError(err). WithFields(logrus.Fields{ "queueLen": len(queue), "batchTimeout": c.conf.Behavior.BatchTimeout.String(), }). Error(logPart) - ext.LogError(span, err2) - c.setLastErr(err2) + err = errors.Wrap(err, logPart) + c.setLastErr(err) // checkErrorCounter is updated within client.GetPeerRateLimits(). for _, r := range queue { @@ -475,7 +499,7 @@ func (c *PeerClient) sendQueue(ctx context.Context, queue []*request) { // Unlikely, but this avoids a panic if something wonky happens if len(resp.RateLimits) != len(queue) { err = errors.New("server responded with incorrect rate limit list size") - ext.LogError(span, err) + span.RecordError(err) for _, r := range queue { checkErrorCounter.WithLabelValues("Item mismatch").Add(1) diff --git a/tracing/tracing.go b/tracing/tracing.go deleted file mode 100644 index d19df368..00000000 --- a/tracing/tracing.go +++ /dev/null @@ -1,92 +0,0 @@ -/* -Copyright 2018-2022 Mailgun Technologies Inc - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package tracing - -// General purpose Opentracing functions. - -import ( - "context" - "fmt" - "runtime" - "strconv" - "time" - - "github.com/opentracing/opentracing-go" -) - -// Start a span using the full function name as the operation name. -// When done, be sure to call span.Finish(). -func StartSpan(ctx context.Context) (opentracing.Span, context.Context) { - operationName, fileTag := getCallerInfoForTracing(2) - - span, ctx2 := opentracing.StartSpanFromContext(ctx, operationName) - span.SetTag("file", fileTag) - - return span, ctx2 -} - -// Start a span using given operation name. -// When done, be sure to call span.Finish(). -func StartNamedSpan(ctx context.Context, operationName string) (opentracing.Span, context.Context) { - _, fileTag := getCallerInfoForTracing(2) - - span, ctx2 := opentracing.StartSpanFromContext(ctx, operationName) - span.SetTag("file", fileTag) - - return span, ctx2 -} - -func getCallerInfoForTracing(stackIndex int) (string, string) { - fileTag := "unknown" - operationName := "unknown" - pc, file, line, callerOk := runtime.Caller(stackIndex) - - if callerOk { - operationName = runtime.FuncForPC(pc).Name() - fileTag = file + ":" + strconv.Itoa(line) - } - - return operationName, fileTag -} - -// Log a message to span. -// Optionally pass additional key/value pairs. -func LogInfo(span opentracing.Span, message string, keyValues ...interface{}) { - args := append( - []interface{}{ - "event", "info", - "event.message", message, - }, - keyValues..., - ) - span.LogKV(args...) -} - -// Do context.WithTimeout and log details of the deadline origin. -func ContextWithTimeout(ctx context.Context, duration time.Duration) (context.Context, context.CancelFunc) { - deadline := time.Now().Add(duration) - _, fn, line, _ := runtime.Caller(1) - - if span := opentracing.SpanFromContext(ctx); span != nil { - LogInfo(span, "Set context deadline", - "deadline", deadline.Format(time.RFC3339), - "source", fmt.Sprintf("%s:%d", fn, line), - ) - } - - return context.WithTimeout(ctx, duration) -}