diff --git a/.env.sample b/.env.sample index b4fbaf48..e15d7d49 100644 --- a/.env.sample +++ b/.env.sample @@ -17,6 +17,8 @@ SERVER_CORS_ALLOWED_HEADERS="" SERVER_GRPC_PORT=8081 + + WORKER_BUFFER_CHANNEL_SIZE=5 WORKER_BUFFER_FLUSH_TIMEOUT_MS=5000 WORKER_POOL_SIZE=5 @@ -32,7 +34,9 @@ PUBLISHER_KAFKA_CLIENT_STATISTICS_INTERVAL_MS=5000 PUBLISHER_KAFKA_CLIENT_QUEUE_BUFFERING_MAX_MESSAGES=100000 PUBLISHER_KAFKA_FLUSH_INTERVAL_MS=1000 +METRIC_RUNTIME_STATS_RECORD_INTERVAL_MS=1000 +METRIC_PROMETHEUS_ENABLED="true" METRIC_STATSD_ADDRESS=":8125" -METRIC_STATSD_FLUSH_PERIOD_MS=100 +METRIC_STATSD_FLUSH_PERIOD_MS=1000 LOG_LEVEL="info" diff --git a/.env.test b/.env.test index 8de597de..96e11c73 100644 --- a/.env.test +++ b/.env.test @@ -33,7 +33,9 @@ PUBLISHER_KAFKA_CLIENT_STATISTICS_INTERVAL_MS=5000 PUBLISHER_KAFKA_CLIENT_QUEUE_BUFFERING_MAX_MESSAGES=100000 PUBLISHER_KAFKA_FLUSH_INTERVAL_MS=1000 +METRIC_RUNTIME_STATS_RECORD_INTERVAL_MS=1000 +METRIC_PROMETHEUS_ENABLED="true" METRIC_STATSD_ADDRESS=":8125" -METRIC_STATSD_FLUSH_PERIOD_MS=100 +METRIC_STATSD_FLUSH_PERIOD_MS=1000 LOG_LEVEL="info" diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 5f98b0ce..46f7aab6 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -9,9 +9,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Setup Go - uses: actions/setup-go@v2.1.3 + uses: actions/setup-go@v3 with: - go-version: "1.14" + go-version: "1.18" - name: Checkout repo uses: actions/checkout@v2 with: @@ -25,9 +25,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Setup Go - uses: actions/setup-go@v2.1.3 + uses: actions/setup-go@v3 with: - go-version: "1.14" + go-version: "1.18" - name: Install Protoc uses: arduino/setup-protoc@v1 - uses: actions/checkout@v2 diff --git a/.github/workflows/integration-test.yaml b/.github/workflows/integration-test.yaml index ebcede12..4762526c 100644 --- a/.github/workflows/integration-test.yaml +++ b/.github/workflows/integration-test.yaml @@ -14,6 +14,10 @@ jobs: uses: arduino/setup-protoc@v1 - name: Checkout repo uses: actions/checkout@v2 + - name: Setup Go + uses: actions/setup-go@v3 + with: + go-version: "1.18" - name: Copy integration config run: cp .env.test .env - name: Run Raccoon diff --git a/Dockerfile b/Dockerfile index 5d845d44..de3d0150 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.14 +FROM golang:1.18 WORKDIR /app RUN apt-get update && apt-get install unzip --no-install-recommends --assume-yes @@ -10,7 +10,8 @@ RUN PROTOC_ZIP=protoc-3.17.3-linux-x86_64.zip && \ COPY . . RUN make build -FROM debian:buster-slim + +FROM debian:bookworm-slim WORKDIR /app COPY --from=0 /app/raccoon ./raccoon COPY . . diff --git a/README.md b/README.md index 351d24d9..f200e121 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ You can consume the published events from the host machine by using `localhost:9 Prerequisite: -- You need to have [GO](https://golang.org/) 1.14 or above installed +- You need to have [GO](https://golang.org/) 1.18 or above installed - You need `protoc` [installed](https://github.com/protocolbuffers/protobuf#protocol-compiler-installation) ```sh diff --git a/app/server.go b/app/server.go index b99b3df4..d1d2ef3a 100644 --- a/app/server.go +++ b/app/server.go @@ -63,7 +63,7 @@ func shutDownServer(ctx context.Context, cancel context.CancelFunc, httpServices Until then we fall back to approximation */ eventsInChannel := len(bufferChannel) * 7 logger.Info(fmt.Sprintf("Outstanding unprocessed events in the channel, data lost ~ (No batches %d * 5 events) = ~%d", len(bufferChannel), eventsInChannel)) - metrics.Count("kafka_messages_delivered_total", eventsInChannel+eventsInProducer, "success=false") + metrics.Count("kafka_messages_delivered_total", int64(eventsInChannel+eventsInProducer), map[string]string{"success": "false", "conn_group": "NA", "event_type": "NA"}) logger.Info("Exiting server") cancel() default: @@ -73,20 +73,19 @@ func shutDownServer(ctx context.Context, cancel context.CancelFunc, httpServices } func reportProcMetrics() { - t := time.Tick(config.MetricStatsd.FlushPeriodMs) + t := time.Tick(config.MetricInfo.RuntimeStatsRecordInterval) m := &runtime.MemStats{} for { <-t - metrics.Gauge("server_go_routines_count_current", runtime.NumGoroutine(), "") - + metrics.Gauge("server_go_routines_count_current", runtime.NumGoroutine(), map[string]string{}) runtime.ReadMemStats(m) - metrics.Gauge("server_mem_heap_alloc_bytes_current", m.HeapAlloc, "") - metrics.Gauge("server_mem_heap_inuse_bytes_current", m.HeapInuse, "") - metrics.Gauge("server_mem_heap_objects_total_current", m.HeapObjects, "") - metrics.Gauge("server_mem_stack_inuse_bytes_current", m.StackInuse, "") - metrics.Gauge("server_mem_gc_triggered_current", m.LastGC/1000, "") - metrics.Gauge("server_mem_gc_pauseNs_current", m.PauseNs[(m.NumGC+255)%256]/1000, "") - metrics.Gauge("server_mem_gc_count_current", m.NumGC, "") - metrics.Gauge("server_mem_gc_pauseTotalNs_current", m.PauseTotalNs, "") + metrics.Gauge("server_mem_heap_alloc_bytes_current", m.HeapAlloc, map[string]string{}) + metrics.Gauge("server_mem_heap_inuse_bytes_current", m.HeapInuse, map[string]string{}) + metrics.Gauge("server_mem_heap_objects_total_current", m.HeapObjects, map[string]string{}) + metrics.Gauge("server_mem_stack_inuse_bytes_current", m.StackInuse, map[string]string{}) + metrics.Gauge("server_mem_gc_triggered_current", m.LastGC/1000, map[string]string{}) + metrics.Gauge("server_mem_gc_pauseNs_current", m.PauseNs[(m.NumGC+255)%256]/1000, map[string]string{}) + metrics.Gauge("server_mem_gc_count_current", m.NumGC, map[string]string{}) + metrics.Gauge("server_mem_gc_pauseTotalNs_current", m.PauseTotalNs, map[string]string{}) } } diff --git a/config/load.go b/config/load.go index 014ec4ae..3c579f78 100644 --- a/config/load.go +++ b/config/load.go @@ -21,13 +21,16 @@ func Load() { viper.ReadInConfig() logConfigLoader() + publisherKafkaConfigLoader() serverConfigLoader() serverWsConfigLoader() serverGRPCConfigLoader() serverCorsConfigLoader() workerConfigLoader() + metricCommonConfigLoader() metricStatsdConfigLoader() + metricPrometheusConfigLoader() eventDistributionConfigLoader() eventConfigLoader() } diff --git a/config/metric.go b/config/metric.go index 81c071be..2eca643d 100644 --- a/config/metric.go +++ b/config/metric.go @@ -9,17 +9,50 @@ import ( ) var MetricStatsd metricStatsdCfg +var MetricPrometheus metricPrometheusCfg +var MetricInfo metricInfoCfg type metricStatsdCfg struct { + Enabled bool Address string FlushPeriodMs time.Duration } +type metricPrometheusCfg struct { + Enabled bool + Port int + Path string +} + +type metricInfoCfg struct { + RuntimeStatsRecordInterval time.Duration +} + func metricStatsdConfigLoader() { + viper.SetDefault("METRIC_STATSD_ENABLED", false) viper.SetDefault("METRIC_STATSD_ADDRESS", ":8125") viper.SetDefault("METRIC_STATSD_FLUSH_PERIOD_MS", 10000) MetricStatsd = metricStatsdCfg{ + Enabled: util.MustGetBool("METRIC_STATSD_ENABLED"), Address: util.MustGetString("METRIC_STATSD_ADDRESS"), FlushPeriodMs: util.MustGetDuration("METRIC_STATSD_FLUSH_PERIOD_MS", time.Millisecond), } } + +func metricPrometheusConfigLoader() { + viper.SetDefault("METRIC_PROMETHEUS_ENABLED", false) + viper.SetDefault("METRIC_PROMETHEUS_PORT", 9090) + viper.SetDefault("METRIC_PROMETHEUS_PATH", "/metrics") + MetricPrometheus = metricPrometheusCfg{ + Enabled: util.MustGetBool("METRIC_PROMETHEUS_ENABLED"), + Port: util.MustGetInt("METRIC_PROMETHEUS_PORT"), + Path: util.MustGetString("METRIC_PROMETHEUS_PATH"), + } +} + +func metricCommonConfigLoader() { + viper.SetDefault("METRIC_RUNTIME_STATS_RECORD_INTERVAL_MS", 10000) + MetricInfo = metricInfoCfg{ + RuntimeStatsRecordInterval: util.MustGetDuration("METRIC_RUNTIME_STATS_RECORD_INTERVAL_MS", time.Millisecond), + } +} diff --git a/docker-compose.yml b/docker-compose.yml index 7d047213..030f52ed 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,6 +3,7 @@ version: '3.9' networks: cs-network: + services: zookeeper: image: confluentinc/cp-zookeeper:5.1.2 @@ -41,14 +42,14 @@ services: cs: build: context: . - command: ["/bin/sh", "-c", "./raccoon"] + command: [ "/bin/sh", "-c", "./raccoon" ] hostname: cs container_name: cs stdin_open: true tty: true depends_on: - kafka - - telegraf + # - telegraf environment: SERVER_WEBSOCKET_PORT: "8080" SERVER_WEBSOCKET_CHECK_ORIGIN: "true" @@ -74,6 +75,7 @@ services: PUBLISHER_KAFKA_CLIENT_STATISTICS_INTERVAL_MS: 5000 PUBLISHER_KAFKA_CLIENT_QUEUE_BUFFERING_MAX_MESSAGES: 100000 PUBLISHER_KAFKA_FLUSH_INTERVAL_MS: 1000 + METRIC_PROMETHEUS_ENABLED: "true" METRIC_STATSD_ADDRESS: "telegraf:8125" METRIC_STATSD_FLUSH_PERIOD_MS: 100 LOG_LEVEL: "info" @@ -82,11 +84,11 @@ services: - "8081:8081" networks: - cs-network - telegraf: - image: telegraf - volumes: - - ./.telegraf.sample.conf:/etc/telegraf/telegraf.conf:ro - ports: - - "8125:8125" - networks: - - cs-network + # telegraf: + # image: telegraf + # volumes: + # - ./.telegraf.sample.conf:/etc/telegraf/telegraf.conf:ro + # ports: + # - "8125:8125" + # networks: + # - cs-network diff --git a/docs/docs/reference/configurations.md b/docs/docs/reference/configurations.md index fa3088e8..1e2db350 100644 --- a/docs/docs/reference/configurations.md +++ b/docs/docs/reference/configurations.md @@ -249,6 +249,20 @@ Upon shutdown, the publisher will try to finish processing events in buffer befo ## Metric +### `METRIC_RUNTIME_STATS_RECORD_INTERVAL_MS` + +The time interval between recording runtime stats of the application in the insturmentation. It's recommended to keep this value equivalent to flush interval when using statsd and your collector's scrape interval when using prometheus as your instrumentation. + +- Type `Optional` +- Default Value: `10000` + +### `METRIC_STATSD_ENABLED` + +Flag to enable export of statsd metric + +- Type `Optional` +- Default value: `false` + ### `METRIC_STATSD_ADDRESS` Address to reports the service metrics. @@ -263,6 +277,27 @@ Interval for the service to push metrics. - Type `Optional` - Default value: `10000` +### `METRIC_PROMETHEUS_ENABLED` + +Flag to enable a prometheus http server to expose metrics. + +- Type `Optional` +- Default value: `false` + +### `METRIC_PROMETHEUS_PATH` + +The path at which prometheus server should serve metrics. + +- Type `Optional` +- Default value: `/metrics` + +### `METRIC_PROMETHEUS_PORT` + +The port number on which prometheus server will be listening for metric scraping requests. + +- Type `Optional` +- Default value: `9090` + ## Log ### `LOG_LEVEL` diff --git a/docs/docs/reference/metrics.md b/docs/docs/reference/metrics.md index 575521b5..032ba992 100644 --- a/docs/docs/reference/metrics.md +++ b/docs/docs/reference/metrics.md @@ -53,15 +53,30 @@ Duration of alive connection per session per connection - Type: `Timing` - Tags: `conn_group=*` +### `conn_close_err_count` + +Number of connection close errors encountered + +- Type: `Count` +- Tags: NA + ## Kafka Publisher ### `kafka_messages_delivered_total` -Number of delivered events to Kafka +Number of delivered events to Kafka. The metric also contains false increments. To find the true value, one should use the difference between this and `kafka_messages_undelivered_total` metric for the same tag/labels. + +- Type: `Count` +- Tags: `success=false` `success=true` `conn_group=*` `event_type=*` + +### `kafka_messages_undelivered_total` + +The count of false increments done by `kafka_messages_delivered_total`. To be used in conjunction with the former for accurate metrics. - Type: `Count` - Tags: `success=false` `success=true` `conn_group=*` `event_type=*` + ### `kafka_unknown_topic_failure_total` Number of delivery failure caused by topic does not exist in kafka. @@ -102,6 +117,29 @@ Broker latency / round-trip time in microseconds - Type: `Gauge` - Tags: `broker=broker_nodes` +### `ack_event_rtt_ms` + +Time taken from ack function called by kafka producer to processed by the ack handler. + +- Type: `Timing` +- Tags: NA + +### `event_rtt_ms` + +Time taken from event is consumed from the queue to be acked by the ack handler. + +- Type: `Timing` +- Tags: NA + +### `kafka_producebulk_tt_ms` + +Response time of produce batch method of the kafka producer + +- Type `Timing` +- Tags: NA + + + ## Resource Usage ### `server_mem_gc_triggered_current` @@ -178,6 +216,13 @@ Number of events received in requests - Type: `Count` - Tags: `conn_group=*` `event_type=*` +### `events_duplicate_total` + +Number of duplicate events + +- Type: `Count` +- Tags: `conn_group=*` `reason=*` + ### `batches_read_total` Request count diff --git a/go.mod b/go.mod index 0452492d..1000ae7c 100644 --- a/go.mod +++ b/go.mod @@ -1,16 +1,47 @@ module github.com/raystack/raccoon -go 1.14 +go 1.18 require ( github.com/confluentinc/confluent-kafka-go v1.9.3-RC3 github.com/gorilla/handlers v1.5.1 - github.com/gorilla/mux v1.7.4 - github.com/gorilla/websocket v1.4.2 - github.com/sirupsen/logrus v1.6.0 - github.com/spf13/viper v1.7.0 - github.com/stretchr/testify v1.7.1 - google.golang.org/grpc v1.46.0 + github.com/gorilla/mux v1.8.0 + github.com/gorilla/websocket v1.5.0 + github.com/prometheus/client_golang v1.16.0 + github.com/sirupsen/logrus v1.9.3 + github.com/spf13/cast v1.5.1 + github.com/spf13/viper v1.16.0 + github.com/stretchr/testify v1.8.4 + google.golang.org/grpc v1.58.0 google.golang.org/protobuf v1.31.0 gopkg.in/alexcesaro/statsd.v2 v2.0.0 ) + +require ( + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/felixge/httpsnoop v1.0.1 // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/pelletier/go-toml/v2 v2.0.8 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/prometheus/client_model v0.3.0 // indirect + github.com/prometheus/common v0.42.0 // indirect + github.com/prometheus/procfs v0.10.1 // indirect + github.com/spf13/afero v1.9.5 // indirect + github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/stretchr/objx v0.5.0 // indirect + github.com/subosito/gotenv v1.4.2 // indirect + golang.org/x/net v0.12.0 // indirect + golang.org/x/sys v0.10.0 // indirect + golang.org/x/text v0.11.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum index 3bfadc15..9ab1ef9f 100644 --- a/go.sum +++ b/go.sum @@ -3,39 +3,57 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= 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/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/actgardner/gogen-avro/v10 v10.1.0/go.mod h1:o+ybmVjEa27AAr35FRqU98DJu1fXES56uXniYFv4yDA= github.com/actgardner/gogen-avro/v10 v10.2.1/go.mod h1:QUhjeHPchheYmMDni/Nx7VB0RsT/ee8YIgGY/xpEQgQ= github.com/actgardner/gogen-avro/v9 v9.1.0/go.mod h1:nyTj6wPqDJoxM3qdnjcLv+EnMDSDFqE0qDpva2QRmKc= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 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/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -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/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 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/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/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= @@ -43,50 +61,48 @@ github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/confluentinc/confluent-kafka-go v1.9.3-RC3 h1:urDeBIsNr0hgRf3nZn66SHtdBO/4DmEDSsMWquaolmo= github.com/confluentinc/confluent-kafka-go v1.9.3-RC3/go.mod h1:NlSjbxG73kJM0iKUC6/CDbMnY3H4WF6e+YFBlfLffi8= -github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +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.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/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/frankban/quicktest v1.2.2/go.mod h1:Qh/WofXFeiAFII1aEBu529AtJo6Zg2VHscnEsbBnJ20= github.com/frankban/quicktest v1.7.2/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o= github.com/frankban/quicktest v1.10.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y= github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +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/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= @@ -96,8 +112,9 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -108,56 +125,51 @@ github.com/google/go-cmp v0.2.1-0.20190312032427-6f77996f0c42/go.mod h1:8QqcDgzr 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= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/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.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20211008130755-947d60d73cc0/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= -github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc= -github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hamba/avro v1.5.6/go.mod h1:3vNT0RLXXpFm2Tb/5KC71ZRJlOroggq1Rcitb6k4Fr8= -github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -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-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= -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-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/heetch/avro v0.3.1/go.mod h1:4xn38Oz/+hiEUTpbVfGVLfvOg0yKLlRP7Q9+gJJILgA= github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA= +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= github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= github.com/invopop/jsonschema v0.4.0/go.mod h1:O9uiLokuu0+MGFlyiaqtWxwqJm41/+8Nj0lD7A36YH0= github.com/jhump/gopoet v0.0.0-20190322174617-17282ff210b3/go.mod h1:me9yfT6IJSlOL3FCfrg+L6yzUEZ+5jW6WHt4Sk+UPUI= @@ -165,25 +177,17 @@ github.com/jhump/gopoet v0.1.0/go.mod h1:me9yfT6IJSlOL3FCfrg+L6yzUEZ+5jW6WHt4Sk+ github.com/jhump/goprotoc v0.5.0/go.mod h1:VrbvcYrQOrTi3i0Vf+m+oqQWk9l72mjkJCYo7UvLHRQ= github.com/jhump/protoreflect v1.11.0/go.mod h1:U7aMIjN0NWq9swDP7xDdoMfRHb35uiuTd3Z9nFXJf5E= github.com/jhump/protoreflect v1.12.0/go.mod h1:JytZfP5d0r8pVNLZvai7U/MCuTWITgrI4tTg7puQFKI= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/juju/qthttptest v0.1.1/go.mod h1:aTlAv8TYaflIiTDIQYzxnl1QdPjAg8Q8qJMErpKy6A4= -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/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= 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= -github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= 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= @@ -192,109 +196,97 @@ github.com/linkedin/goavro v2.1.0+incompatible/go.mod h1:bBCwI2eGYpUI/4820s67MEl github.com/linkedin/goavro/v2 v2.10.0/go.mod h1:UgQUb2N/pmueQYH9bfqFioWxzYCZXSfF8Jw03O5sjqA= github.com/linkedin/goavro/v2 v2.10.1/go.mod h1:UgQUb2N/pmueQYH9bfqFioWxzYCZXSfF8Jw03O5sjqA= github.com/linkedin/goavro/v2 v2.11.1/go.mod h1:UgQUb2N/pmueQYH9bfqFioWxzYCZXSfF8Jw03O5sjqA= -github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= -github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -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/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/go-homedir v1.0.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/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= -github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nrwiersma/avro-benchmarks v0.0.0-20210913175520-21aec48c8f76/go.mod h1:iKyFMidsk/sVYONJRE372sJuX/QTRPacU7imPqqsu7g= -github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= +github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= 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/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= +github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= +github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= +github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= +github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= github.com/rogpeppe/clock v0.0.0-20190514195947-2896927a307a/go.mod h1:4r5QyqhjIWCcK8DO4KMclc5Iknq5qVBAlbYYzAbUScQ= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/santhosh-tekuri/jsonschema/v5 v5.0.0/go.mod h1:FKdcjfQW6rpZSnxxUvEA5H/cDPdvJ/SZJQLWWXWGrZ0= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM= -github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= +github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= +github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= +github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +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/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc= +github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg= 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/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 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.3.1-0.20190311161405-34c6fa2dc709/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.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= -github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= +github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 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.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -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= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/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= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +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-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= @@ -304,17 +296,22 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +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/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-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-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/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= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -323,63 +320,115 @@ golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +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-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200505041828-1ed23360d12c/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= +golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= 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= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/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-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= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/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-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/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= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/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-20211007075335-d3039528d8ac h1:oN6lz7iLW/YC7un8pq+9bOLyXrprv2+DKfkJY+2LJJw= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 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-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-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 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= @@ -389,23 +438,69 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= 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= 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= google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +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/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -415,21 +510,59 @@ google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98 google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20220503193339-ba3ae3f07e29 h1:DJUvgAPiJWeMBiT+RzBVcJGQN7bAEWS5UEoMshES9xs= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20220503193339-ba3ae3f07e29/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= google.golang.org/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.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= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.46.0 h1:oCjezcn6g6A75TGoKYBPgKmVBLexhYLM6MebdrPApP8= google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.58.0 h1:32JY8YpPMSR45K+c3o6b8VL73V+rR8k+DeMIr4vRH8o= +google.golang.org/grpc v1.58.0/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= 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= @@ -438,6 +571,7 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= 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= @@ -445,36 +579,35 @@ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alexcesaro/statsd.v2 v2.0.0 h1:FXkZSCZIH17vLCO5sO2UucTHsH9pc+17F6pl3JVCwMc= gopkg.in/alexcesaro/statsd.v2 v2.0.0/go.mod h1:i0ubccKGzBVNBpdGV5MocxyA/XlLUJzA7SLonnE4drU= gopkg.in/avro.v0 v0.0.0-20171217001914-a730b5802183/go.mod h1:FvqrFXt+jCsyQibeRv4xxEJBL5iG2DDW5aeJwzDiq4A= 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= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/errgo.v1 v1.0.0/go.mod h1:CxwszS/Xz1C49Ucd2i6Zil5UToP1EmyrFhKaMVbg1mk= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/httprequest.v1 v1.2.1/go.mod h1:x2Otw96yda5+8+6ZeWwHIJTFkEHWP/qP8pJOzqEtWPM= -gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= -gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/retry.v1 v1.0.3/go.mod h1:FJkXmWiMaAo7xB+xhvDF59zhfjDWyzmyAxiT4dB688g= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/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= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/metrics/metric_test.go b/metrics/metric_test.go new file mode 100644 index 00000000..1f1e9389 --- /dev/null +++ b/metrics/metric_test.go @@ -0,0 +1,147 @@ +package metrics + +import ( + "os" + "testing" + "time" + + "github.com/raystack/raccoon/config" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +type mockMetricInstrument struct { + mock.Mock +} + +func (m *mockMetricInstrument) Increment(metricName string, labels map[string]string) error { + args := m.Called(metricName, labels) + err := args.Get(0) + if err != nil { + return args.Get(0).(error) + } else { + return nil + } +} + +func (m *mockMetricInstrument) Count(metricName string, count int64, labels map[string]string) error { + args := m.Called(metricName, count, labels) + err := args.Get(0) + if err != nil { + return args.Get(0).(error) + } else { + return nil + } + +} + +func (m *mockMetricInstrument) Gauge(metricName string, value interface{}, labels map[string]string) error { + args := m.Called(metricName, value, labels) + err := args.Get(0) + if err != nil { + return args.Get(0).(error) + } else { + return nil + } +} + +func (m *mockMetricInstrument) Histogram(metricName string, value int64, labels map[string]string) error { + args := m.Called(metricName, value, labels) + err := args.Get(0) + if err != nil { + return args.Get(0).(error) + } else { + return nil + } +} + +func (m *mockMetricInstrument) Close() { + m.Called() +} + +func Test_Prometheus_Setup(t *testing.T) { + config.MetricPrometheus.Enabled = true + config.MetricStatsd.Enabled = false + config.MetricPrometheus.Path = "/metrics" + config.MetricPrometheus.Port = 8080 + Setup() + prometheusInstrument, ok := instrument.(*PrometheusCollector) + assert.True(t, ok, "prometheus collector was not initialised") + assert.NotNil(t, prometheusInstrument) + os.Unsetenv("METRIC_PROMETHEUS_ENABLED") + Close() + time.Sleep(5 * time.Second) +} + +func Test_Error_On_Both_Enabled(t *testing.T) { + config.MetricPrometheus.Enabled = true + config.MetricStatsd.Enabled = true + assert.Error(t, Setup()) + os.Setenv("METRIC_STATSD_ENABLED", "false") + os.Setenv("METRIC_PROMETHEUS_ENABLED", "false") + defer Close() +} + +func Test_Count_Calls_Instrument_Count(t *testing.T) { + mockInstrumentImpl := &mockMetricInstrument{} + instrument = mockInstrumentImpl + metricName := "abcd" + countValue := int64(9000) + labels := map[string]string{"xyz": "ques", "alpha": "beta"} + mockInstrumentImpl.On("Count", metricName, countValue, labels).Return(nil) + err := Count(metricName, countValue, labels) + assert.NoError(t, err) + mockInstrumentImpl.AssertCalled(t, "Count", metricName, countValue, labels) + mockInstrumentImpl.AssertNumberOfCalls(t, "Count", 1) +} + +func Test_Gauge_Calls_Instrument_Gauge(t *testing.T) { + mockInstrumentImpl := &mockMetricInstrument{} + instrument = mockInstrumentImpl + metricName := "abcd" + countValue := int64(9000) + labels := map[string]string{"xyz": "ques", "alpha": "beta"} + mockInstrumentImpl.On("Gauge", metricName, countValue, labels).Return(nil) + err := Gauge(metricName, countValue, labels) + assert.NoError(t, err) + mockInstrumentImpl.AssertCalled(t, "Gauge", metricName, countValue, labels) + mockInstrumentImpl.AssertNumberOfCalls(t, "Gauge", 1) +} + +func Test_Histogram_Calls_Instrument_Histogram(t *testing.T) { + mockInstrumentImpl := &mockMetricInstrument{} + instrument = mockInstrumentImpl + metricName := "abcd" + countValue := int64(9000) + labels := map[string]string{"xyz": "ques", "alpha": "beta"} + mockInstrumentImpl.On("Histogram", metricName, countValue, labels).Return(nil) + err := Histogram(metricName, countValue, labels) + assert.NoError(t, err) + mockInstrumentImpl.AssertCalled(t, "Histogram", metricName, countValue, labels) + mockInstrumentImpl.AssertNumberOfCalls(t, "Histogram", 1) +} + +func Test_Close_Calls_Instrument_Close(t *testing.T) { + mockInstrumentImpl := &mockMetricInstrument{} + instrument = mockInstrumentImpl + mockInstrumentImpl.On("Close") + Close() + mockInstrumentImpl.AssertCalled(t, "Close") +} + +func Test_Close_Does_Not_Panic_On_Nil_Instrument(t *testing.T) { + assert.NotPanics(t, Close) +} + +func Test_ReturnsErrWhenCalledithNilInstrument(t *testing.T) { + instrument = nil + metricName := "abcd" + countValue := int64(9000) + labels := map[string]string{"xyz": "ques", "alpha": "beta"} + err := Count(metricName, countValue, labels) + assert.Error(t, err) + err = Gauge(metricName, countValue, labels) + assert.Error(t, err) + err = Histogram(metricName, countValue, labels) + assert.Error(t, err) +} diff --git a/metrics/metrics.go b/metrics/metrics.go new file mode 100644 index 00000000..83ec8b24 --- /dev/null +++ b/metrics/metrics.go @@ -0,0 +1,119 @@ +package metrics + +import ( + "errors" + + "github.com/raystack/raccoon/config" + "github.com/raystack/raccoon/logger" +) + +var instrument MetricInstrument + +type MetricInstrument interface { + Increment(metricName string, labels map[string]string) error + Count(metricName string, count int64, labels map[string]string) error + Gauge(metricName string, value interface{}, labels map[string]string) error + Histogram(metricName string, value int64, labels map[string]string) error + Close() +} + +type voidInstrument struct{} + +func (v voidInstrument) Increment(metricName string, labels map[string]string) error { + return nil +} + +func (v voidInstrument) Count(metricName string, count int64, labels map[string]string) error { + return nil +} + +func (v voidInstrument) Gauge(metricName string, value interface{}, labels map[string]string) error { + return nil +} + +func (v voidInstrument) Histogram(metricName string, value int64, labels map[string]string) error { + return nil +} + +func (v voidInstrument) Close() {} + +func Increment(metricName string, labels map[string]string) error { + if instrument == nil { + logger.Warn("instrumentation is not set for recording metrics") + return errors.New("instrumentation is not set for recording metrics") + } + err := instrument.Increment(metricName, labels) + if err != nil { + logger.Warn(err) + } + return err +} + +func Count(metricName string, count int64, labels map[string]string) error { + if instrument == nil { + logger.Warn("instrumentation is not set for recording metrics") + return errors.New("instrumentation is not set for recording metrics") + } + err := instrument.Count(metricName, count, labels) + if err != nil { + logger.Warn(err) + } + return err +} + +func Gauge(metricName string, value interface{}, labels map[string]string) error { + if instrument == nil { + logger.Warn("instrumentation is not set for recording metrics") + return errors.New("instrumentation is not set for recording metrics") + } + err := instrument.Gauge(metricName, value, labels) + if err != nil { + logger.Warn(err) + } + return err +} + +func Histogram(metricName string, value int64, labels map[string]string) error { + if instrument == nil { + logger.Warn("instrumentation is not set for recording metrics") + return errors.New("instrumentation is not set for recording metrics") + } + err := instrument.Histogram(metricName, value, labels) + if err != nil { + logger.Warn(err) + } + return err +} + +func Setup() error { + + if config.MetricPrometheus.Enabled && config.MetricStatsd.Enabled { + return errors.New("only one instrumentation tool can be enabled") + } + + if config.MetricPrometheus.Enabled { + prometheus, err := initPrometheusCollector() + if err != nil { + return err + } + instrument = prometheus + } + if config.MetricStatsd.Enabled { + statsD, err := initStatsd() + if err != nil { + return err + } + instrument = statsD + } + return nil +} + +func SetVoid() { + instrument = voidInstrument{} +} + +func Close() { + if instrument != nil { + instrument.Close() + } +} diff --git a/metrics/prometheus.go b/metrics/prometheus.go new file mode 100644 index 00000000..25aff9c5 --- /dev/null +++ b/metrics/prometheus.go @@ -0,0 +1,272 @@ +package metrics + +import ( + "context" + "fmt" + "math" + "net/http" + "time" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promhttp" + "github.com/raystack/raccoon/config" + "github.com/raystack/raccoon/logger" + "github.com/spf13/cast" +) + +type CounterVec interface { + With(labels prometheus.Labels) prometheus.Counter + Collect(chan<- prometheus.Metric) + Describe(chan<- *prometheus.Desc) +} + +type GaugeVec interface { + With(labels prometheus.Labels) prometheus.Gauge + Collect(chan<- prometheus.Metric) + Describe(chan<- *prometheus.Desc) +} + +type HistogramVec interface { + With(labels prometheus.Labels) prometheus.Observer + Collect(chan<- prometheus.Metric) + Describe(chan<- *prometheus.Desc) +} + +type PrometheusCollector struct { + registry *prometheus.Registry + counters map[string]CounterVec + gauges map[string]GaugeVec + histogram map[string]HistogramVec + server *http.Server +} + +func initPrometheusCollector() (*PrometheusCollector, error) { + serveMux := &http.ServeMux{} + server := &http.Server{Addr: fmt.Sprintf(":%d", config.MetricPrometheus.Port), Handler: serveMux} + p := &PrometheusCollector{ + counters: getCounterMap(), + gauges: getGaugeMap(), + histogram: getHistogramMap(), + registry: prometheus.NewRegistry(), + server: server, + } + err := p.Register() + if err != nil { + return nil, err + } + serveMux.Handle(config.MetricPrometheus.Path, promhttp.HandlerFor(p.registry, promhttp.HandlerOpts{Registry: p.registry})) + go server.ListenAndServe() + return p, nil + +} + +func (p *PrometheusCollector) Count(metricName string, count int64, labels map[string]string) error { + counter, ok := p.counters[metricName] + if !ok { + return fmt.Errorf("invalid counter metric %s", metricName) + } + counter.With(labels).Add(float64(count)) + return nil +} + +func (p *PrometheusCollector) Increment(metricName string, labels map[string]string) error { + counter, ok := p.counters[metricName] + if !ok { + return fmt.Errorf("invalid counter metric %s", metricName) + } + counter.With(labels).Inc() + return nil +} + +func (p *PrometheusCollector) Gauge(metricName string, value interface{}, labels map[string]string) error { + gauge, ok := p.gauges[metricName] + if !ok { + return fmt.Errorf("invalid gauge metric %s", metricName) + } + floatVal, err := cast.ToFloat64E(value) + if err != nil { + return err + } + if math.IsNaN(floatVal){ + return fmt.Errorf("nan value was requested to be instrumented for %s", metricName) + } + gauge.With(labels).Set(floatVal) + return nil +} + +func (p *PrometheusCollector) Histogram(metricName string, value int64, labels map[string]string) error { + histogram, ok := p.histogram[metricName] + if !ok { + return fmt.Errorf("invalid histogram metric %s", metricName) + } + floatVal := float64(value) + histogram.With(labels).Observe(floatVal) + return nil +} + +func (p *PrometheusCollector) Register() error { + for _, counter := range p.counters { + err := p.registry.Register(counter) + if err != nil { + return err + } + } + for _, gauge := range p.gauges { + err := p.registry.Register(gauge) + if err != nil { + return err + } + } + for _, histogram := range p.histogram { + err := p.registry.Register(histogram) + if err != nil { + return err + } + } + return nil +} + +func (p *PrometheusCollector) Close() { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*15) + logger.Info("shutting down prometheus metric server") + err := p.server.Shutdown(ctx) + if err != nil { + logger.Warn("error shutting down logger") + } + defer cancel() +} + +func getCounterMap() map[string]CounterVec { + counters := make(map[string]CounterVec) + counters["kafka_messages_delivered_total"] = prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "kafka_messages_delivered_total", + Help: "Number of delivered events to Kafka"}, []string{"success", "conn_group", "event_type"}) + counters["kafka_messages_undelivered_total"] = prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "kafka_messages_undelivered_total", + Help: "Number of delivered events to Kafka which failed while reading delivery report"}, []string{"success", "conn_group", "event_type"}) + counters["events_rx_bytes_total"] = prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "events_rx_bytes_total", + Help: "Total byte receieved in requests"}, []string{"conn_group", "event_type"}) + counters["events_rx_total"] = prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "events_rx_total", + Help: "Number of events received in requests"}, []string{"conn_group", "event_type"}) + counters["kafka_unknown_topic_failure_total"] = prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "kafka_unknown_topic_failure_total", + Help: "Number of delivery failure caused by topic does not exist in kafka."}, []string{"topic", "event_type"}) + counters["batches_read_total"] = prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "batches_read_total", + Help: "Request count"}, []string{"status", "reason", "conn_group"}) + counters["events_duplicate_total"] = prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "events_duplicate_total", + Help: "Total Number of Duplicate events recieved by the server"}, []string{"conn_group", "reason"}) + counters["server_ping_failure_total"] = prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "server_ping_failure_total", + Help: "Total ping that server fails to send"}, []string{"conn_group"}) + counters["conn_close_err_count"] = prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "conn_close_err_count", + Help: "Total Number of Connection Errors When Trying To Close"}, []string{}) + counters["user_connection_failure_total"] = prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "user_connection_failure_total", + Help: "Number of fail connections established to the server"}, []string{"conn_group", "reason"}) + counters["user_connection_success_total"] = prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "user_connection_success_total", + Help: "Number of successful connections established to the server"}, []string{"conn_group"}) + counters["server_pong_failure_total"] = prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "server_pong_failure_total", + Help: "Total pong that server fails to send"}, []string{"conn_group"}) + return counters +} + +func getGaugeMap() map[string]GaugeVec { + gauges := make(map[string]GaugeVec) + gauges["server_go_routines_count_current"] = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "server_go_routines_count_current", + Help: "Number of goroutine spawn in a single flush"}, []string{}) + gauges["server_mem_heap_alloc_bytes_current"] = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "server_mem_heap_alloc_bytes_current", + Help: "Bytes of allocated heap objects"}, []string{}) + gauges["server_mem_heap_inuse_bytes_current"] = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "server_mem_heap_inuse_bytes_current", + Help: "HeapInuse is bytes in in-use spans"}, []string{}) + gauges["server_mem_heap_objects_total_current"] = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "server_mem_heap_objects_total_current", + Help: "Number of allocated heap objects"}, []string{}) + gauges["server_mem_stack_inuse_bytes_current"] = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "server_mem_stack_inuse_bytes_current", + Help: "Bytes in stack spans"}, []string{}) + gauges["server_mem_gc_triggered_current"] = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "server_mem_gc_triggered_current", + Help: "The time the last garbage collection finished in Unix timestamp"}, []string{}) + gauges["server_mem_gc_pauseNs_current"] = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "server_mem_gc_pauseNs_current", + Help: "Circular buffer of recent GC stop-the-world in Unix timestamp"}, []string{}) + gauges["server_mem_gc_count_current"] = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "server_mem_gc_count_current", + Help: "The number of completed GC cycle"}, []string{}) + gauges["server_mem_gc_pauseTotalNs_current"] = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "server_mem_gc_pauseTotalNs_current", + Help: "The cumulative nanoseconds in GC stop-the-world pauses since the program started"}, []string{}) + gauges["kafka_tx_messages_total"] = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "kafka_tx_messages_total", + Help: "Total number of messages transmitted produced to Kafka brokers."}, []string{}) + gauges["kafka_tx_messages_bytes_total"] = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "kafka_tx_messages_bytes_total", + Help: "Total number of message bytes (including framing, such as per-Message framing and MessageSet/batch framing) transmitted to Kafka brokers"}, []string{}) + gauges["kafka_brokers_tx_total"] = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "kafka_brokers_tx_total", + Help: "Total number of requests sent to Kafka brokers"}, []string{"broker"}) + gauges["kafka_brokers_tx_bytes_total"] = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "kafka_brokers_tx_bytes_total", + Help: "Total number of bytes transmitted to Kafka brokers"}, []string{"broker"}) + gauges["kafka_brokers_rtt_average_milliseconds"] = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "kafka_brokers_rtt_average_milliseconds", + Help: "Broker latency / round-trip time in microseconds"}, []string{"broker"}) + gauges["connections_count_current"] = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "connections_count_current", + Help: "Number of alive connections"}, []string{"conn_group"}) + return gauges +} + +func getHistogramMap() map[string]HistogramVec { + histogram := make(map[string]HistogramVec) + histogram["ack_event_rtt_ms"] = prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Name: "ack_event_rtt_ms", + Help: "Time taken from ack function called by kafka producer to processed by the ack handler.", + Buckets: []float64{5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000}, + }, []string{}) + histogram["event_rtt_ms"] = prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Name: "event_rtt_ms", + Help: "Time taken from event is consumed from the queue to be acked by the ack handler.", + Buckets: []float64{5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000}, + }, []string{}) + histogram["user_session_duration_milliseconds"] = prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Name: "user_session_duration_milliseconds", + Help: "Duration of alive connection per session per connection", + Buckets: []float64{1000, 10000, 100000, 600000, 3600000}, + }, []string{"conn_group"}) + histogram["batch_idle_in_channel_milliseconds"] = prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Name: "batch_idle_in_channel_milliseconds", + Help: "Duration from when the request is received to when the request is processed. High value of this metric indicates the publisher is slow.", + Buckets: []float64{5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000}, + }, []string{"worker"}) + histogram["kafka_producebulk_tt_ms"] = prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Name: "kafka_producebulk_tt_ms", + Buckets: []float64{5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000}, + }, []string{}) + histogram["event_processing_duration_milliseconds"] = prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Name: "event_processing_duration_milliseconds", + Help: "Duration from the time request is sent to the time events are published. This metric is calculated per event by following formula (PublishedTime - SentTime)/CountEvents", + Buckets: []float64{5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000}, + }, []string{"conn_group"}) + histogram["worker_processing_duration_milliseconds"] = prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Name: "worker_processing_duration_milliseconds", + Help: "Duration from the time request is processed to the time events are published. This metric is calculated per event by following formula (PublishedTime - ProcessedTime)/CountEvents", + Buckets: []float64{5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000}, + }, []string{"worker"}) + histogram["server_processing_latency_milliseconds"] = prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Name: "server_processing_latency_milliseconds", + Help: "Duration from the time request is receieved to the time events are published. This metric is calculated per event by following formula`(PublishedTime - ReceievedTime)/CountEvents`", + Buckets: []float64{5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000}, + }, []string{"conn_group"}) + return histogram +} diff --git a/metrics/prometheus_test.go b/metrics/prometheus_test.go new file mode 100644 index 00000000..ce459d97 --- /dev/null +++ b/metrics/prometheus_test.go @@ -0,0 +1,270 @@ +package metrics + +import ( + "fmt" + "io" + "net/http" + "strconv" + "testing" + "time" + + "github.com/prometheus/client_golang/prometheus" + "github.com/raystack/raccoon/config" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/suite" +) + +type PrometheusTestSuite struct { + suite.Suite + instrument *PrometheusCollector +} + +const prometheusPath = "/test_metrics" +const prometheusPort = "9999" + +type mockCounterVec struct { + mock.Mock +} + +// With is a method of mockCounterVec that satisfies the CounterVec interface. +func (c *mockCounterVec) With(labels prometheus.Labels) prometheus.Counter { + args := c.Called(labels) + return args.Get(0).(prometheus.Counter) +} + +// Collect is a method of mockCounterVec that satisfies the CounterVec interface. +func (c *mockCounterVec) Collect(ch chan<- prometheus.Metric) { + c.Called(ch) +} + +// Describe is a method of mockCounterVec that satisfies the CounterVec interface. +func (c *mockCounterVec) Describe(ch chan<- *prometheus.Desc) { + c.Called(ch) +} + +// mockGaugeVec is a mock struct that implements the GaugeVec interface and embeds mock.Mock. +type mockGaugeVec struct { + mock.Mock +} + +// With is a method of mockGaugeVec that satisfies the GaugeVec interface. +func (g *mockGaugeVec) With(labels prometheus.Labels) prometheus.Gauge { + args := g.Called(labels) + return args.Get(0).(prometheus.Gauge) +} + +// Collect is a method of mockGaugeVec that satisfies the GaugeVec interface. +func (g *mockGaugeVec) Collect(ch chan<- prometheus.Metric) { + g.Called(ch) +} + +// Describe is a method of mockGaugeVec that satisfies the GaugeVec interface. +func (g *mockGaugeVec) Describe(ch chan<- *prometheus.Desc) { + g.Called(ch) +} + +// mockHistogramVec is a mock struct that implements the HistogramVec interface and embeds mock.Mock. +type mockHistogramVec struct { + mock.Mock +} + +// With is a method of mockHistogramVec that satisfies the HistogramVec interface. +func (h *mockHistogramVec) With(labels prometheus.Labels) prometheus.Observer { + args := h.Called(labels) + return args.Get(0).(prometheus.Observer) +} + +// Collect is a method of mockHistogramVec that satisfies the HistogramVec interface. +func (h *mockHistogramVec) Collect(ch chan<- prometheus.Metric) { + h.Called(ch) +} + +// Describe is a method of mockHistogramVec that satisfies the HistogramVec interface. +func (h *mockHistogramVec) Describe(ch chan<- *prometheus.Desc) { + h.Called(ch) +} + +type mockCounter struct { + mock.Mock + prometheus.Counter +} + +func (m *mockCounter) Add(f float64) { + m.Called(f) +} + +func (m *mockCounter) Inc() { + m.Called() +} + +type mockGauge struct { + mock.Mock + prometheus.Gauge +} + +func (m *mockGauge) Set(f float64) { + m.Called(f) +} + +type mockObserver struct { + mock.Mock +} + +func (m *mockObserver) Observe(f float64) { + m.Called(f) +} + +func (promSuite *PrometheusTestSuite) Test_Prometheus_Collector_Metrics_Initialised() { + numCounters := 12 + numGauge := 15 + numHistogram := 8 + var err error + promSuite.instrument, err = initPrometheusCollector() + assert.NoError(promSuite.T(), err, "error while initialising prometheus collector") + assert.Equal(promSuite.T(), numCounters, len(promSuite.instrument.counters), "number of prometheus counters do not match expected count") + assert.Equal(promSuite.T(), numGauge, len(promSuite.instrument.gauges), "number of prometheus gauges do not match expected count") + assert.Equal(promSuite.T(), numHistogram, len(promSuite.instrument.histogram), "number of prometheus histogram do not match expected count") +} + +func (promSuite *PrometheusTestSuite) Test_PrometheusCollector_Metrics_Registered() { + var err error + promSuite.instrument, err = initPrometheusCollector() + assert.NoError(promSuite.T(), err) + for metricName, collector := range promSuite.instrument.counters { + assert.True(promSuite.T(), promSuite.instrument.registry.Unregister(collector), fmt.Sprintf("%s counter not registered", metricName)) + } + for metricName, collector := range promSuite.instrument.gauges { + assert.True(promSuite.T(), promSuite.instrument.registry.Unregister(collector), fmt.Sprintf("%s gauge not registered", metricName)) + } + for metricName, collector := range promSuite.instrument.histogram { + assert.True(promSuite.T(), promSuite.instrument.registry.Unregister(collector), fmt.Sprintf("%s counter not registered", metricName)) + } +} + +func (promSuite *PrometheusTestSuite) Test_Prometheus_Collector_MetricServer_Initialised() { + var err error + promSuite.instrument, err = initPrometheusCollector() + assert.NoError(promSuite.T(), err) + client := http.Client{Timeout: 5 * time.Second} + time.Sleep(2 * time.Second) + req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("http://:%s%s", prometheusPort, prometheusPath), nil) + assert.NoError(promSuite.T(), err) + res, err := client.Do(req) + assert.NoError(promSuite.T(), err) + defer io.Copy(io.Discard, res.Body) + defer res.Body.Close() + assert.Equal(promSuite.T(), http.StatusOK, res.StatusCode) + bodyLength, err := io.Copy(io.Discard, res.Body) + assert.NoError(promSuite.T(), err) + assert.NotZero(promSuite.T(), bodyLength) +} + +func (promSuite *PrometheusTestSuite) Test_Prometheus_Counter_Working() { + sampleCounterMetric1 := "kafka_unknown_topic_failure_total" + sampleCounterMetric2 := "batches_read_total" + mockCounterVec1 := mockCounterVec{} + mockCounterVec2 := mockCounterVec{} + mockCounter1 := mockCounter{} + mockCounter2 := mockCounter{} + callArg1 := int64(35) + labels1 := map[string]string{"topic": "test", "event_type": "abc"} + promLabels1 := prometheus.Labels{"topic": "test", "event_type": "abc"} + labels2 := map[string]string{"status": "success", "reason": "unknown", "conn_group": "abc"} + promLabels2 := prometheus.Labels{"status": "success", "reason": "unknown", "conn_group": "abc"} + var err error + promSuite.instrument, err = initPrometheusCollector() + assert.NoError(promSuite.T(), err) + promSuite.instrument.counters[sampleCounterMetric1] = &mockCounterVec1 + promSuite.instrument.counters[sampleCounterMetric2] = &mockCounterVec2 + mockCounterVec1.On("With", promLabels1).Return(&mockCounter1) + mockCounter1.On("Add", float64(callArg1)) + mockCounterVec2.On("With", promLabels2).Return(&mockCounter2) + mockCounter2.On("Inc") + err = promSuite.instrument.Count(sampleCounterMetric1, int64(callArg1), labels1) + assert.NoError(promSuite.T(), err) + err = promSuite.instrument.Increment(sampleCounterMetric2, labels2) + assert.NoError(promSuite.T(), err) + mockCounterVec1.AssertCalled(promSuite.T(), "With", promLabels1) + mockCounterVec2.AssertCalled(promSuite.T(), "With", promLabels2) + mockCounterVec1.AssertNumberOfCalls(promSuite.T(), "With", 1) + mockCounterVec2.AssertNumberOfCalls(promSuite.T(), "With", 1) + mockCounter1.AssertNumberOfCalls(promSuite.T(), "Add", 1) + mockCounter2.AssertNumberOfCalls(promSuite.T(), "Inc", 1) + mockCounter1.AssertCalled(promSuite.T(), "Add", float64(callArg1)) + mockCounter2.AssertCalled(promSuite.T(), "Inc") +} + +func (promSuite *PrometheusTestSuite) Test_Prometheus_Gauge_Working() { + sampleGaugeMetric := "server_go_routines_count_current" + mockGaugeVec := mockGaugeVec{} + mockGauge := mockGauge{} + callArg := int64(35) + labels := map[string]string{"topic": "test", "event_type": "abc"} + promLabels := prometheus.Labels{"topic": "test", "event_type": "abc"} + var err error + promSuite.instrument, err = initPrometheusCollector() + assert.NoError(promSuite.T(), err) + promSuite.instrument.gauges[sampleGaugeMetric] = &mockGaugeVec + mockGaugeVec.On("With", promLabels).Return(&mockGauge) + mockGauge.On("Set", float64(callArg)) + err = promSuite.instrument.Gauge(sampleGaugeMetric, int64(callArg), labels) + assert.NoError(promSuite.T(), err) + mockGaugeVec.AssertCalled(promSuite.T(), "With", promLabels) + mockGaugeVec.AssertNumberOfCalls(promSuite.T(), "With", 1) + mockGauge.AssertNumberOfCalls(promSuite.T(), "Set", 1) + mockGauge.AssertCalled(promSuite.T(), "Set", float64(callArg)) +} + +func (promSuite *PrometheusTestSuite) Test_Prometheus_Histogram_Working() { + sampleHistogramMetric := "server_processing_latency_milliseconds" + mockHistogramVec := mockHistogramVec{} + mockObserver := mockObserver{} + callArg := int64(35) + labels := map[string]string{"conn_group": "--default--"} + promLabels := prometheus.Labels{"conn_group": "--default--"} + var err error + promSuite.instrument, err = initPrometheusCollector() + assert.NoError(promSuite.T(), err) + promSuite.instrument.histogram[sampleHistogramMetric] = &mockHistogramVec + mockHistogramVec.On("With", promLabels).Return(&mockObserver) + mockObserver.On("Observe", float64(callArg)) + err = promSuite.instrument.Histogram(sampleHistogramMetric, callArg, labels) + assert.NoError(promSuite.T(), err) + mockHistogramVec.AssertCalled(promSuite.T(), "With", promLabels) + mockHistogramVec.AssertNumberOfCalls(promSuite.T(), "With", 1) + mockObserver.AssertCalled(promSuite.T(), "Observe", float64(callArg)) + mockObserver.AssertNumberOfCalls(promSuite.T(), "Observe", 1) +} + +func (promSuite *PrometheusTestSuite) Test_Prometheus_Gauge_Error_On_Invalid_Input() { + sampleGaugeMetric := "server_go_routines_count_current" + mockGaugeVec := mockGaugeVec{} + callArg := "abc" + labels := map[string]string{"topic": "test", "event_type": "abc"} + var err error + promSuite.instrument, err = initPrometheusCollector() + assert.NoError(promSuite.T(), err) + promSuite.instrument.gauges[sampleGaugeMetric] = &mockGaugeVec + err = promSuite.instrument.Gauge(sampleGaugeMetric, callArg, labels) + assert.Error(promSuite.T(), err) + mockGaugeVec.AssertNotCalled(promSuite.T(), "With") +} + +func TestPrometheusSuite(t *testing.T) { + suite.Run(t, new(PrometheusTestSuite)) +} + +func (suite *PrometheusTestSuite) SetupTest() { + var err error + config.MetricPrometheus.Enabled = true + config.MetricPrometheus.Path = prometheusPath + config.MetricPrometheus.Port, err = strconv.Atoi(prometheusPort) + assert.NoError(suite.T(), err) +} + +func (promSuite *PrometheusTestSuite) TearDownTest() { + if promSuite.instrument != nil { + promSuite.instrument.Close() + } +} diff --git a/metrics/statsd.go b/metrics/statsd.go index fc154fef..59290265 100644 --- a/metrics/statsd.go +++ b/metrics/statsd.go @@ -2,36 +2,28 @@ package metrics import ( "fmt" + "strings" "github.com/raystack/raccoon/config" "github.com/raystack/raccoon/logger" client "gopkg.in/alexcesaro/statsd.v2" ) -var instance *Statsd - type Statsd struct { c *client.Client } -func (s *Statsd) count(bucket string, i int, tags string) { - s.c.Count(withTags(bucket, tags), i) -} - -func (s *Statsd) timing(bucket string, t int64, tags string) { - s.c.Timing(withTags(bucket, tags), t) -} - -func (s *Statsd) increment(bucket string, tags string) { - s.c.Increment(withTags(bucket, tags)) -} - -func (s *Statsd) decrement(bucket string, tags string) { - s.c.Count(withTags(bucket, tags), -1) -} - -func (s *Statsd) gauge(bucket string, val interface{}, tags string) { - s.c.Gauge(withTags(bucket, tags), val) +func initStatsd() (*Statsd, error) { + c, err := client.New( + client.Address(config.MetricStatsd.Address), + client.FlushPeriod(config.MetricStatsd.FlushPeriodMs)) + if err != nil { + logger.Errorf("StatsD Set up failed to create client: %s", err.Error()) + return nil, err + } + return &Statsd{ + c: c, + }, nil } func (s *Statsd) Close() { @@ -42,68 +34,35 @@ func withTags(bucket, tags string) string { return fmt.Sprintf("%v,%v", bucket, tags) } -func Setup() error { - if instance == nil { - c, err := client.New( - client.Address(config.MetricStatsd.Address), - client.FlushPeriod(config.MetricStatsd.FlushPeriodMs)) - if err != nil { - logger.Errorf("StatsD Set up failed to create client: %s", err.Error()) - return err - } - - instance = &Statsd{ - c: c, - } - } +func (s *Statsd) Count(metricName string, count int64, labels map[string]string) error { + tags := translateLabelIntoTags(labels) + s.c.Count(withTags(metricName, tags), int(count)) return nil -} -func Count(bucket string, i int, tags string) { - err := Setup() - if err == nil { - instance.count(bucket, i, tags) - } -} - -func Timing(bucket string, t int64, tags string) { - err := Setup() - if err == nil { - instance.timing(bucket, t, tags) - } -} - -func Increment(bucket string, tags string) { - err := Setup() - if err == nil { - instance.increment(bucket, tags) - } } -func Decrement(bucket string, tags string) { - err := Setup() - if err == nil { - instance.decrement(bucket, tags) - } +func (s *Statsd) Histogram(metricName string, value int64, labels map[string]string) error { + tags := translateLabelIntoTags(labels) + s.c.Timing(withTags(metricName,tags), value) + return nil } -func Gauge(bucket string, val interface{}, tags string) { - err := Setup() - if err == nil { - instance.gauge(bucket, val, tags) - } +func (s *Statsd) Increment(metricName string, labels map[string]string) error { + tags := translateLabelIntoTags(labels) + s.c.Increment(withTags(metricName, tags)) + return nil } -func Close() { - err := Setup() - if err == nil { - instance.Close() - } +func (s *Statsd) Gauge(metricName string, value interface{}, labels map[string]string) error { + tags := translateLabelIntoTags(labels) + s.c.Gauge(withTags(metricName, tags), value) + return nil } -func SetVoid() { - c, _ := client.New(client.Mute(true)) - instance = &Statsd{ - c: c, +func translateLabelIntoTags(labels map[string]string) string { + labelArr := make([]string, len(labels)) + for key, value := range labels { + labelArr = append(labelArr, fmt.Sprintf("%s=%s", key, value)) } + return strings.Join(labelArr, ",") } diff --git a/publisher/kafka.go b/publisher/kafka.go index 2221891b..bc7b088d 100644 --- a/publisher/kafka.go +++ b/publisher/kafka.go @@ -60,16 +60,17 @@ func (pr *Kafka) ProduceBulk(events []*pb.Event, connGroup string, deliveryChann err := pr.kp.Produce(message, deliveryChannel) if err != nil { - metrics.Increment("kafka_messages_delivered_total", fmt.Sprintf("success=false,conn_group=%s,event_type=%s", connGroup, event.Type)) + metrics.Increment("kafka_messages_delivered_total", map[string]string{"success": "false", "conn_group": connGroup, "event_type": event.Type}) if err.Error() == "Local: Unknown topic" { errors[order] = fmt.Errorf("%v %s", err, topic) - metrics.Increment("kafka_unknown_topic_failure_total", fmt.Sprintf("topic=%s,event_type=%s,conn_group=%s", topic, event.Type, connGroup)) + metrics.Increment("kafka_unknown_topic_failure_total", map[string]string{"topic": topic, "event_type": event.Type, "conn_group": connGroup}) } else { errors[order] = err } continue } - metrics.Increment("kafka_messages_delivered_total", fmt.Sprintf("success=true,conn_group=%s,event_type=%s", connGroup, event.Type)) + metrics.Increment("kafka_messages_delivered_total", map[string]string{"success": "true", "conn_group": connGroup, "event_type": event.Type}) + totalProcessed++ } // Wait for deliveryChannel as many as processed @@ -78,8 +79,8 @@ func (pr *Kafka) ProduceBulk(events []*pb.Event, connGroup string, deliveryChann m := d.(*kafka.Message) if m.TopicPartition.Error != nil { eventType := events[i].Type - metrics.Decrement("kafka_messages_delivered_total", fmt.Sprintf("success=true,conn_group=%s,event_type=%s", connGroup, eventType)) - metrics.Increment("kafka_messages_delivered_total", fmt.Sprintf("success=false,conn_group=%s,event_type=%s", connGroup, eventType)) + metrics.Increment("kafka_messages_undelivered_total", map[string]string{"success": "true", "conn_group": connGroup, "event_type": eventType}) + metrics.Increment("kafka_messages_delivered_total", map[string]string{"success": "false", "conn_group": connGroup, "event_type": eventType}) order := m.Opaque.(int) errors[order] = m.TopicPartition.Error } @@ -99,16 +100,16 @@ func (pr *Kafka) ReportStats() { json.Unmarshal([]byte(e.String()), &stats) brokers := stats["brokers"].(map[string]interface{}) - metrics.Gauge("kafka_tx_messages_total", stats["txmsgs"], "") - metrics.Gauge("kafka_tx_messages_bytes_total", stats["txmsg_bytes"], "") + metrics.Gauge("kafka_tx_messages_total", stats["txmsgs"], map[string]string{}) + metrics.Gauge("kafka_tx_messages_bytes_total", stats["txmsg_bytes"], map[string]string{}) for _, broker := range brokers { brokerStats := broker.(map[string]interface{}) rttValue := brokerStats["rtt"].(map[string]interface{}) nodeName := strings.Split(brokerStats["nodename"].(string), ":")[0] - metrics.Gauge("kafka_brokers_tx_total", brokerStats["tx"], fmt.Sprintf("broker=%s", nodeName)) - metrics.Gauge("kafka_brokers_tx_bytes_total", brokerStats["txbytes"], fmt.Sprintf("broker=%s", nodeName)) - metrics.Gauge("kafka_brokers_rtt_average_milliseconds", rttValue["avg"], fmt.Sprintf("broker=%s", nodeName)) + metrics.Gauge("kafka_brokers_tx_total", brokerStats["tx"], map[string]string{"broker": nodeName}) + metrics.Gauge("kafka_brokers_tx_bytes_total", brokerStats["txbytes"], map[string]string{"broker": nodeName}) + metrics.Gauge("kafka_brokers_rtt_average_milliseconds", rttValue["avg"], map[string]string{"broker": nodeName}) } default: diff --git a/services/grpc/handler.go b/services/grpc/handler.go index 528551a6..1b021d65 100644 --- a/services/grpc/handler.go +++ b/services/grpc/handler.go @@ -3,7 +3,6 @@ package grpc import ( "context" "errors" - "fmt" "time" "github.com/raystack/raccoon/collection" @@ -46,7 +45,7 @@ func (h *Handler) SendEvent(ctx context.Context, req *pb.SendEventRequest) (*pb. timeConsumed := time.Now() - metrics.Increment("batches_read_total", fmt.Sprintf("status=success,conn_group=%s", identifier.Group)) + metrics.Increment("batches_read_total", map[string]string{"status": "success", "conn_group": identifier.Group, "reason": "NA"}) h.sendEventCounters(req.Events, identifier.Group) responseChannel := make(chan *pb.SendEventResponse, 1) @@ -110,6 +109,6 @@ func (h *Handler) Ack(responseChannel chan *pb.SendEventResponse, reqGuid, connG func (h *Handler) sendEventCounters(events []*pb.Event, group string) { for _, e := range events { - metrics.Increment("events_rx_total", fmt.Sprintf("conn_group=%s,event_type=%s", group, e.Type)) + metrics.Increment("events_rx_total", map[string]string{"conn_group": group, "event_type": e.Type}) } } diff --git a/services/rest/handler.go b/services/rest/handler.go index 547b8d13..ce87f6e8 100644 --- a/services/rest/handler.go +++ b/services/rest/handler.go @@ -59,7 +59,7 @@ func (h *Handler) RESTAPIHandler(rw http.ResponseWriter, r *http.Request) { serde, ok := h.serDeMap[contentType] if !ok { - metrics.Increment("batches_read_total", "status=failed,reason=unknowncontentype") + metrics.Increment("batches_read_total", map[string]string{"status": "failed", "reason": "unknowncontentype", "conn_group": "NA"}) logger.Errorf("[rest.GetRESTAPIHandler] invalid content type %s", contentType) rw.WriteHeader(http.StatusBadRequest) _, err := res.SetCode(pb.Code_CODE_BAD_REQUEST).SetStatus(pb.Status_STATUS_ERROR).SetReason("invalid content type"). @@ -82,7 +82,7 @@ func (h *Handler) RESTAPIHandler(rw http.ResponseWriter, r *http.Request) { } if r.Body == nil { - metrics.Increment("batches_read_total", fmt.Sprintf("status=failed,reason=emptybody,conn_group=%s", identifier.Group)) + metrics.Increment("batches_read_total", map[string]string{"status": "failed", "reason": "emptybody", "conn_group": identifier.Group}) logger.Errorf("[rest.GetRESTAPIHandler] %s no body", identifier) rw.WriteHeader(http.StatusBadRequest) _, err := res.SetCode(pb.Code_CODE_BAD_REQUEST).SetStatus(pb.Status_STATUS_ERROR).SetReason("no body present"). @@ -99,7 +99,7 @@ func (h *Handler) RESTAPIHandler(rw http.ResponseWriter, r *http.Request) { b, err := ioutil.ReadAll(r.Body) if err != nil { logger.Errorf(fmt.Sprintf("[rest.GetRESTAPIHandler] %s error reading request body, error: %v", identifier, err)) - metrics.Increment("batches_read_total", fmt.Sprintf("status=failed,reason=readerr,conn_group=%s", identifier.Group)) + metrics.Increment("batches_read_total", map[string]string{"status": "failed", "reason": "readerr", "conn_group": identifier.Group}) rw.WriteHeader(http.StatusInternalServerError) _, err := res.SetCode(pb.Code_CODE_INTERNAL_ERROR).SetStatus(pb.Status_STATUS_ERROR).SetReason("deserialization failure"). SetSentTime(time.Now().Unix()).Write(rw, s) @@ -114,7 +114,7 @@ func (h *Handler) RESTAPIHandler(rw http.ResponseWriter, r *http.Request) { if err := d(b, req); err != nil { logger.Errorf("[rest.GetRESTAPIHandler] error while calling d.Deserialize() for %s, error: %s", identifier, err) - metrics.Increment("batches_read_total", fmt.Sprintf("status=failed,reason=serde,conn_group=%s", identifier.Group)) + metrics.Increment("batches_read_total", map[string]string{"status": "failed", "reason": "serde", "conn_group": identifier.Group}) rw.WriteHeader(http.StatusBadRequest) _, err := res.SetCode(pb.Code_CODE_BAD_REQUEST).SetStatus(pb.Status_STATUS_ERROR).SetReason("deserialization failure"). SetSentTime(time.Now().Unix()).Write(rw, s) @@ -124,7 +124,7 @@ func (h *Handler) RESTAPIHandler(rw http.ResponseWriter, r *http.Request) { return } - metrics.Increment("batches_read_total", fmt.Sprintf("status=success,conn_group=%s", identifier.Group)) + metrics.Increment("batches_read_total", map[string]string{"status": "success", "conn_group": identifier.Group, "reason": "NA"}) h.sendEventCounters(req.Events, identifier.Group) resChannel := make(chan struct{}, 1) @@ -187,7 +187,7 @@ func (h *Handler) Ack(rw http.ResponseWriter, resChannel chan struct{}, s serial func (h *Handler) sendEventCounters(events []*pb.Event, group string) { for _, e := range events { - metrics.Count("events_rx_bytes_total", len(e.EventBytes), fmt.Sprintf("conn_group=%s,event_type=%s", group, e.Type)) - metrics.Increment("events_rx_total", fmt.Sprintf("conn_group=%s,event_type=%s", group, e.Type)) + metrics.Count("events_rx_bytes_total", int64(len(e.EventBytes)), map[string]string{"conn_group": group, "event_type": e.Type}) + metrics.Increment("events_rx_total", map[string]string{"conn_group": group, "event_type": e.Type}) } } diff --git a/services/rest/service.go b/services/rest/service.go index a4c5309c..5942cc45 100644 --- a/services/rest/service.go +++ b/services/rest/service.go @@ -2,7 +2,6 @@ package rest import ( "context" - "fmt" "net/http" "time" @@ -57,11 +56,11 @@ func pingHandler(w http.ResponseWriter, r *http.Request) { } func reportConnectionMetrics(conn connection.Table) { - t := time.Tick(config.MetricStatsd.FlushPeriodMs) + t := time.Tick(config.MetricInfo.RuntimeStatsRecordInterval) for { <-t for k, v := range conn.TotalConnectionPerGroup() { - metrics.Gauge("connections_count_current", v, fmt.Sprintf("conn_group=%s", k)) + metrics.Gauge("connections_count_current", v, map[string]string{"conn_group": k}) } } } diff --git a/services/rest/websocket/ack.go b/services/rest/websocket/ack.go index 82d0969a..8767c3c7 100644 --- a/services/rest/websocket/ack.go +++ b/services/rest/websocket/ack.go @@ -23,16 +23,16 @@ type AckInfo struct { func AckHandler(ch <-chan AckInfo) { for c := range ch { ackTim := time.Since(c.AckTimeConsumed) - metrics.Timing("ack_event_rtt_ms", ackTim.Milliseconds(), "") + metrics.Histogram("ack_event_rtt_ms", ackTim.Milliseconds(), map[string]string{}) tim := time.Since(c.TimeConsumed) if c.Err != nil { - metrics.Timing("event_rtt_ms", tim.Milliseconds(), "") + metrics.Histogram("event_rtt_ms", tim.Milliseconds(), map[string]string{}) writeFailedResponse(c.Conn, c.serializer, c.MessageType, c.RequestGuid, c.Err) continue } - metrics.Timing("event_rtt_ms", tim.Milliseconds(), "") + metrics.Histogram("event_rtt_ms", tim.Milliseconds(), map[string]string{}) writeSuccessResponse(c.Conn, c.serializer, c.MessageType, c.RequestGuid) } } diff --git a/services/rest/websocket/connection/conn.go b/services/rest/websocket/connection/conn.go index 591b341c..4e46fda7 100644 --- a/services/rest/websocket/connection/conn.go +++ b/services/rest/websocket/connection/conn.go @@ -1,7 +1,6 @@ package connection import ( - "fmt" "time" "github.com/gorilla/websocket" @@ -32,7 +31,7 @@ func (c *Conn) Ping(writeWaitInterval time.Duration) error { func (c *Conn) Close() { if err := c.conn.Close(); err != nil { logger.Errorf("[Connection Error] %v", err) - metrics.Increment("conn_close_err_count", "") + metrics.Increment("conn_close_err_count", map[string]string{}) } c.calculateSessionTime() c.closeHook(*c) @@ -41,5 +40,5 @@ func (c *Conn) Close() { func (c *Conn) calculateSessionTime() { connectionTime := time.Since(c.connectedAt) logger.Debugf("[websocket.calculateSessionTime] %s, total time connected in minutes: %v", c.Identifier, connectionTime.Minutes()) - metrics.Timing("user_session_duration_milliseconds", connectionTime.Milliseconds(), fmt.Sprintf("conn_group=%s", c.Identifier.Group)) + metrics.Histogram("user_session_duration_milliseconds", connectionTime.Milliseconds(), map[string]string{"conn_group": c.Identifier.Group}) } diff --git a/services/rest/websocket/connection/upgrader.go b/services/rest/websocket/connection/upgrader.go index 994e95dc..f22182f2 100644 --- a/services/rest/websocket/connection/upgrader.go +++ b/services/rest/websocket/connection/upgrader.go @@ -64,7 +64,7 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request) (Conn, error) conn, err := u.gorillaUg.Upgrade(w, r, nil) if err != nil { - metrics.Increment("user_connection_failure_total", fmt.Sprintf("reason=ugfailure,conn_group=%s", identifier.Group)) + metrics.Increment("user_connection_failure_total", map[string]string{"reason": "ugfailure", "conn_group": identifier.Group}) return Conn{}, fmt.Errorf("failed to upgrade %s: %v", identifier, err) } err = u.Table.Store(identifier) @@ -74,7 +74,7 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request) (Conn, error) conn.WriteMessage(websocket.BinaryMessage, duplicateConnResp) conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(1008, "duplicate connection: "+identifier.ID)) - metrics.Increment("user_connection_failure_total", fmt.Sprintf("reason=exists,conn_group=%s", identifier.Group)) + metrics.Increment("user_connection_failure_total", map[string]string{"reason": "exists", "conn_group": identifier.Group}) conn.Close() return Conn{}, fmt.Errorf("disconnecting connection %s: already connected", identifier) } @@ -83,13 +83,13 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request) (Conn, error) maxConnResp := createEmptyErrorResponse(pb.Code_CODE_MAX_CONNECTION_LIMIT_REACHED, err.Error()) conn.WriteMessage(websocket.BinaryMessage, maxConnResp) conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(1008, "Max connection reached")) - metrics.Increment("user_connection_failure_total", fmt.Sprintf("reason=serverlimit,conn_group=%s", identifier.Group)) + metrics.Increment("user_connection_failure_total", map[string]string{"reason": "serverlimit", "conn_group": identifier.Group}) conn.Close() return Conn{}, fmt.Errorf("max connection reached") } u.setUpControlHandlers(conn, identifier) - metrics.Increment("user_connection_success_total", fmt.Sprintf("conn_group=%s", identifier.Group)) + metrics.Increment("user_connection_success_total", map[string]string{"conn_group": identifier.Group}) return Conn{ Identifier: identifier, @@ -112,7 +112,7 @@ func (u *Upgrader) setUpControlHandlers(conn *websocket.Conn, identifier identif conn.SetPingHandler(func(s string) error { logger.Debug(fmt.Sprintf("Client %s pinged", identifier)) if err := conn.WriteControl(websocket.PongMessage, []byte(s), time.Now().Add(u.writeWaitInterval)); err != nil { - metrics.Increment("server_pong_failure_total", fmt.Sprintf("conn_group=%s", identifier.Group)) + metrics.Increment("server_pong_failure_total", map[string]string{"conn_group": identifier.Group}) logger.Debug(fmt.Sprintf("Failed to send pong event %s: %v", identifier, err)) } return nil diff --git a/services/rest/websocket/handler.go b/services/rest/websocket/handler.go index 0b0ba156..bdd68e32 100644 --- a/services/rest/websocket/handler.go +++ b/services/rest/websocket/handler.go @@ -84,10 +84,10 @@ func (h *Handler) HandlerWSEvents(w http.ResponseWriter, r *http.Request) { websocket.CloseNoStatusReceived, websocket.CloseAbnormalClosure) { logger.Error(fmt.Sprintf("[websocket.Handler] %s closed abruptly: %v", conn.Identifier, err)) - metrics.Increment("batches_read_total", fmt.Sprintf("status=failed,reason=closeerror,conn_group=%s", conn.Identifier.Group)) + metrics.Increment("batches_read_total", map[string]string{"status": "failed", "reason": "closeerror", "conn_group": conn.Identifier.Group}) break } - metrics.Increment("batches_read_total", fmt.Sprintf("status=failed,reason=unknown,conn_group=%s", conn.Identifier.Group)) + metrics.Increment("batches_read_total", map[string]string{"status": "failed", "reason": "unknown", "conn_group": conn.Identifier.Group}) logger.Error(fmt.Sprintf("[websocket.Handler] reading message failed. Unknown failure for %s: %v", conn.Identifier, err)) //no connection issue here break } @@ -98,21 +98,21 @@ func (h *Handler) HandlerWSEvents(w http.ResponseWriter, r *http.Request) { d, s := serde.deserializer, serde.serializer if err := d(message, payload); err != nil { logger.Error(fmt.Sprintf("[websocket.Handler] reading message failed for %s: %v", conn.Identifier, err)) - metrics.Increment("batches_read_total", fmt.Sprintf("status=failed,reason=serde,conn_group=%s", conn.Identifier.Group)) + metrics.Increment("batches_read_total", map[string]string{"status": "failed", "reason": "serde", "conn_group": conn.Identifier.Group}) writeBadRequestResponse(conn, s, messageType, payload.ReqGuid, err) continue } if config.Server.DedupEnabled { // avoiding processing the same active connection's duplicate events. if h.upgrader.Table.HasBatch(conn.Identifier, payload.ReqGuid) { - metrics.Increment("events_duplicate_total", fmt.Sprintf("reason=duplicate,conn_group=%s", conn.Identifier.Group)) + metrics.Increment("events_duplicate_total", map[string]string{"reason": "duplicate", "conn_group": conn.Identifier.Group}) writeSuccessResponse(conn, s, messageType, payload.ReqGuid) continue } h.upgrader.Table.StoreBatch(conn.Identifier, payload.ReqGuid) } - metrics.Increment("batches_read_total", fmt.Sprintf("status=success,conn_group=%s", conn.Identifier.Group)) + metrics.Increment("batches_read_total", map[string]string{"status": "success", "conn_group": conn.Identifier.Group, "reason": "NA"}) h.sendEventCounters(payload.Events, conn.Identifier.Group) h.collector.Collect(r.Context(), &collection.CollectRequest{ @@ -154,8 +154,8 @@ func (h *Handler) Ack(conn connection.Conn, resChannel chan AckInfo, s serializa func (h *Handler) sendEventCounters(events []*pb.Event, group string) { for _, e := range events { - metrics.Count("events_rx_bytes_total", len(e.EventBytes), fmt.Sprintf("conn_group=%s,event_type=%s", group, e.Type)) - metrics.Increment("events_rx_total", fmt.Sprintf("conn_group=%s,event_type=%s", group, e.Type)) + metrics.Count("events_rx_bytes_total", int64(len(e.EventBytes)), map[string]string{"conn_group": group, "event_type": e.Type}) + metrics.Increment("events_rx_total", map[string]string{"conn_group": group, "event_type": e.Type}) } } diff --git a/services/rest/websocket/pinger.go b/services/rest/websocket/pinger.go index 667ff12f..2b9e32ac 100644 --- a/services/rest/websocket/pinger.go +++ b/services/rest/websocket/pinger.go @@ -25,7 +25,7 @@ func Pinger(c chan connection.Conn, size int, PingInterval time.Duration, WriteW logger.Debug(fmt.Sprintf("Pinging %s ", identifier)) if err := conn.Ping(WriteWaitInterval); err != nil { logger.Error(fmt.Sprintf("[websocket.pingPeer] - Failed to ping %s: %v", identifier, err)) - metrics.Increment("server_ping_failure_total", fmt.Sprintf("conn_group=%s", identifier.Group)) + metrics.Increment("server_ping_failure_total", map[string]string{"conn_group": identifier.Group}) delete(cSet, identifier) } } diff --git a/worker/worker.go b/worker/worker.go index 3cf6cbb8..5cb6ecff 100644 --- a/worker/worker.go +++ b/worker/worker.go @@ -40,14 +40,14 @@ func (w *Pool) StartWorkers() { logger.Info("Running worker: " + workerName) deliveryChan := make(chan kafka.Event, w.deliveryChannelSize) for request := range w.EventsChannel { - metrics.Timing("batch_idle_in_channel_milliseconds", (time.Now().Sub(request.TimePushed)).Milliseconds(), "worker="+workerName) + metrics.Histogram("batch_idle_in_channel_milliseconds", (time.Now().Sub(request.TimePushed)).Milliseconds(), map[string]string{"worker": workerName}) batchReadTime := time.Now() //@TODO - Should add integration tests to prove that the worker receives the same message that it produced, on the delivery channel it created err := w.kafkaProducer.ProduceBulk(request.GetEvents(), request.ConnectionIdentifier.Group, deliveryChan) produceTime := time.Since(batchReadTime) - metrics.Timing("kafka_producebulk_tt_ms", produceTime.Milliseconds(), "") + metrics.Histogram("kafka_producebulk_tt_ms", produceTime.Milliseconds(), map[string]string{}) if request.AckFunc != nil { request.AckFunc(err) @@ -66,10 +66,10 @@ func (w *Pool) StartWorkers() { logger.Debug(fmt.Sprintf("Success sending messages, %v", lenBatch-int64(totalErr))) if lenBatch > 0 { eventTimingMs := time.Since(request.GetSentTime().AsTime()).Milliseconds() / lenBatch - metrics.Timing("event_processing_duration_milliseconds", eventTimingMs, fmt.Sprintf("conn_group=%s", request.ConnectionIdentifier.Group)) + metrics.Histogram("event_processing_duration_milliseconds", eventTimingMs, map[string]string{"conn_group": request.ConnectionIdentifier.Group}) now := time.Now() - metrics.Timing("worker_processing_duration_milliseconds", (now.Sub(batchReadTime).Milliseconds())/lenBatch, "worker="+workerName) - metrics.Timing("server_processing_latency_milliseconds", (now.Sub(request.TimeConsumed)).Milliseconds()/lenBatch, fmt.Sprintf("conn_group=%s", request.ConnectionIdentifier.Group)) + metrics.Histogram("worker_processing_duration_milliseconds", (now.Sub(batchReadTime).Milliseconds())/lenBatch, map[string]string{"worker": workerName}) + metrics.Histogram("server_processing_latency_milliseconds", (now.Sub(request.TimeConsumed)).Milliseconds()/lenBatch, map[string]string{"conn_group": request.ConnectionIdentifier.Group}) } } w.wg.Done()