From c68be5ee38718735abcfedbed068e390cbdcc8d2 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Mon, 22 Jul 2024 07:43:17 +0100 Subject: [PATCH] Updating dependencies --- .env.dist | 14 +- .github/dependabot.yml | 12 + .gitignore | 1 + Makefile | 10 +- README.md | 49 +- docker/connect/Dockerfile | 25 +- docker/connect/debezium-mysql.json | 19 +- docker/connect/entrypoint-wrap.sh | 10 + docker/dev/docker-compose.yml | 63 +- docker/grafana/config/datasource.yml | 2 +- .../{http_requests.json => user.json} | 690 +++++++++++---- docker/otel/otel-collector-config.yml | 38 + docker/prometheus/prometheus.yaml | 6 + docker/prometheus/prometheus.yml | 6 - docker/schema/Dockerfile | 2 +- docker/schema/entrypoint-wrap.sh | 2 +- docker/schema/users-value.json | 389 +++++---- go.mod | 114 +-- go.sum | 824 ++++-------------- golangci.yml | 6 +- internal/bootstrap/bootstrap.go | 14 +- internal/bootstrap/consumer.go | 45 +- internal/bootstrap/router.go | 23 +- internal/bootstrap/storage.go | 33 +- internal/config/config.go | 76 +- internal/consume/consumer.go | 165 ++++ internal/consume/consumer_test.go | 96 ++ internal/consume/prom.go | 132 --- internal/format/format.go | 25 + internal/log/logger.go | 33 +- internal/log/spanlogger.go | 16 +- internal/metrics/metrics.go | 166 ++++ internal/routing/grpc.go | 66 +- internal/routing/http.go | 168 ++-- internal/storage/elastic/user.go | 27 +- internal/storage/redis/user.go | 63 +- internal/telemetry/telemetry.go | 161 ++++ internal/trace/tracer.go | 54 -- internal/user/consume/consumer.go | 207 ----- internal/user/consume/consumer_test.go | 227 ----- internal/user/consume/processor.go | 98 ++- internal/user/consume/processor_test.go | 208 ++++- test/e2e_test.go | 48 +- 43 files changed, 2253 insertions(+), 2180 deletions(-) create mode 100644 .github/dependabot.yml rename docker/grafana/dashboards/{http_requests.json => user.json} (60%) create mode 100644 docker/otel/otel-collector-config.yml create mode 100644 docker/prometheus/prometheus.yaml delete mode 100644 docker/prometheus/prometheus.yml create mode 100644 internal/consume/consumer.go create mode 100644 internal/consume/consumer_test.go delete mode 100644 internal/consume/prom.go create mode 100644 internal/format/format.go create mode 100644 internal/metrics/metrics.go create mode 100644 internal/telemetry/telemetry.go delete mode 100644 internal/trace/tracer.go delete mode 100644 internal/user/consume/consumer.go delete mode 100644 internal/user/consume/consumer_test.go diff --git a/.env.dist b/.env.dist index 8f4a247..dfefc27 100644 --- a/.env.dist +++ b/.env.dist @@ -1,4 +1,4 @@ -MYSQL_DBNAME=go-api-demo +MYSQL_DBNAME=go_api_demo MYSQL_HOST=localhost MYSQL_PASSWORD=password MYSQL_PORT=3306 @@ -7,12 +7,10 @@ MYSQL_USER=user STORAGE_TYPE=sql STORAGE_QUERY_TIMEOUT=3s -METRICS_ENABLED=true -METRICS_COLLECTION_INTERVAL=5s - LOGGING_PRODUCTION=false -TRACING_ENABLED=true +TELEMETRY_ENABLED=true +TELEMETRY_METRICS_COLLECTION_INTERVAL=5s JAEGER_REPORTER_LOG_SPANS=false JAEGER_SAMPLER_TYPE=const @@ -22,13 +20,13 @@ JAEGER_SERVICE_NAME=go-api-demo KAFKA_BROKERS=localhost:9092 KAFKA_USER_CONSUMER_CACHE_GROUP_ID=user-consumer-cache-group-id -KAFKA_USER_CONSUMER_CACHE_TOPIC=go_api_demo_db.go-api-demo.users +KAFKA_USER_CONSUMER_CACHE_TOPIC=mysql.go_api_demo.users KAFKA_USER_CONSUMER_CACHE_MAX_WAIT=1s -KAFKA_USER_CONSUMER_CACHE_REBALANCE_TIMEOUT"=1s +KAFKA_USER_CONSUMER_CACHE_REBALANCE_TIMEOUT=1s KAFKA_USER_CONSUMER_CACHE_IS_ENABLED=true KAFKA_USER_CONSUMER_SEARCH_GROUP_ID=user-consumer-search-group-id -KAFKA_USER_CONSUMER_SEARCH_TOPIC=go_api_demo_db.go-api-demo.users +KAFKA_USER_CONSUMER_SEARCH_TOPIC=mysql.go_api_demo.users KAFKA_USER_CONSUMER_SEARCH_MAX_WAIT=1s KAFKA_USER_CONSUMER_SEARCH_REBALANCE_TIMEOUT=1s KAFKA_USER_CONSUMER_SEARCH_IS_ENABLED=true diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..1cc3888 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +# See GitHub's documentation for more information on this file: +# https://docs.github.com/en/code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/configuration-options-for-dependency-updates +version: 2 +updates: + - package-ecosystem: "docker" + directory: "/" + schedule: + interval: "daily" + - package-ecosystem: "gomod" + directory: "/" + schedule: + interval: "daily" \ No newline at end of file diff --git a/.gitignore b/.gitignore index dc71cd8..defa650 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ bin/go-api-demo generated/*.protoset test/coverage.txt +.vscode \ No newline at end of file diff --git a/Makefile b/Makefile index 83e4aa1..dab0f00 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ SERVICE_NAME=go-api-demo -MYSQL_DSN=mysql://user:password@tcp(127.0.0.1:3306)/go-api-demo +MYSQL_DSN=mysql://user:password@tcp(127.0.0.1:3306)/go_api_demo MYSQL_MIGRATION_PATH=internal/storage/mysql/migrations export HOST_IP=${shell ipconfig getifaddr en0} @@ -63,11 +63,15 @@ endif .PHONY: docker-up docker-up: .env - docker compose -f docker/dev/docker-compose.yml up -d + docker compose -f docker/dev/docker-compose.yml build --no-cache + docker image prune -f + docker compose -f docker/dev/docker-compose.yml up -d --force-recreate .PHONY: docker-down docker-down: - docker rm --force -v go-api-demo-connect go-api-demo-grafana go-api-demo-prometheus go-api-demo-jaeger go-api-demo-redis go-api-demo-elastic go-api-demo-zookeeper go-api-demo-kowl go-api-demo-db go-api-demo-kafka go-api-demo-schema-registry + docker rm --force -v go-api-demo-connect go-api-demo-grafana go-api-demo-prometheus \ + go-api-demo-jaeger go-api-demo-redis go-api-demo-elastic go-api-demo-zookeeper \ + go-api-demo-kowl go-api-demo-db go-api-demo-kafka go-api-demo-schema-registry docker compose -f docker/dev/docker-compose.yml down ################################################################################ diff --git a/README.md b/README.md index 12c672c..d43a563 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ is used as a basis for event-driven cache and search engine population whilst av | [v0.10.0](#v0.10.0) | | | [v0.11.0](#v0.11.0) | | | [v0.12.0](#v0.12.0) | Uses Avro Schema for serialization and deserialization. | +| [v0.13.0](#v0.13.0) | Updating dependencies. | ### Set-up @@ -57,9 +58,21 @@ The _Makefile_ contains commands for building, running and testing the API. * `make test` runs the linter then the tests (see [Tests](#tests)). * `make migrate-up` runs the database migrations for MySQL (see [v0.3.0](#v0.3.0)). +### Setup + +There is a delay between running `make docker-up` and all necessary infrastructure being +available to run the tests and the API. This delay can result in errors when running +the integration tests. Execute `make run` once the tests run successfully. + +``` +make docker-up +make test +make run +``` + ### Tests -Install [testify](https://github.com/stretchr/testify#installation) then run +Install [testify](https://github.com/stretchr/testify#installation) then run: ``` make docker-up @@ -76,6 +89,10 @@ Alternatively, requests can be issued using cURL and [gRPCurl](https://github.com/fullstorydev/grpcurl) (see [v0.2.0](#v0.2.0), [v0.3.0](#v0.3.0), [v0.4.0](#v0.4.0)). +## v0.13.0 + +Version `0.13.0` has been updated to use more recent versions of packages and docker images. A switch from open tracing to open telemetry has also been implemented. + ## v0.12.0 Uses Avro Schema for the serialization of users during CDC and deserialization when @@ -83,13 +100,13 @@ the Kafka consumers populate Redis and Elasticsearch. ### Set-up -There is a delay between running docker-up and all necessary infrastructure being -available to run the tests and the API. This delay can result in errors when running -the integration tests. Execute `make run` once the tests run successfully. +Review the notes for [setup](#setup). - make docker-up - make test - make run +``` +make docker-up +make test +make run +``` The schema are visible through Kowl. @@ -103,20 +120,20 @@ Adds 2 Kafka consumers for populating Elasticsearch. ### Set-up -There is a delay between running docker-up and all necessary infrastructure being -available to run the tests and the API. This delay can result in errors when running -the integration tests. Execute `make run` once the tests run successfully. +Review the notes for [setup](#setup). - make docker-up - make test - make run +``` +make docker-up +make test +make run +``` Running (see [docker](#k6_docker_post) or [local](#k6_local_post)) the [k6](https://k6.io/) script will send 50 requests per second (RPS) to the `POST /user` endpoint for 5 minutes. #### Docker - docker run -e HOST=host.docker.internal -i loadimpact/k6 run - Local @@ -185,7 +202,7 @@ requests per second (RPS) to the `POST /user` endpoint for 5 minutes. #### Docker - docker run -e HOST=host.docker.internal -i loadimpact/k6 run - Local @@ -545,7 +562,7 @@ for the [Grafana](http://localhost:3456) dashboard. #### Docker - docker run -e HOST=host.docker.internal -i loadimpact/k6 run - Local diff --git a/docker/connect/Dockerfile b/docker/connect/Dockerfile index 3b49f18..02cccc1 100644 --- a/docker/connect/Dockerfile +++ b/docker/connect/Dockerfile @@ -1,6 +1,27 @@ -FROM debezium/connect:1.7 +FROM debezium/connect:3.0.0.Final -COPY docker/connect/entrypoint-wrap.sh /entrypoint-wrap.sh COPY docker/connect/debezium-mysql.json /debezium-mysql.json +COPY docker/connect/entrypoint-wrap.sh /entrypoint-wrap.sh + +ENV KAFKA_CONNECT_PLUGINS_DIR=$KAFKA_HOME/connect \ + EXTERNAL_LIBS_DIR=$KAFKA_HOME/external_libs \ + CONNECT_PLUGIN_PATH=$KAFKA_CONNECT_PLUGINS_DIR \ + MAVEN_DEP_DESTINATION=$KAFKA_HOME/libs \ + CONFLUENT_VERSION=7.7.1 \ + AVRO_VERSION=1.12.0 \ + GUAVA_VERSION=33.3.1-jre \ + GUAVA_FAILURE_ACCESS_VERSION=1.0.2 + +RUN docker-maven-download confluent kafka-connect-avro-converter "$CONFLUENT_VERSION" 262d3d4e880e78fa6bb00469fdf10489 && \ + docker-maven-download confluent kafka-connect-avro-data "$CONFLUENT_VERSION" a0b8b5ac8782fc815b059965ae634706 && \ + docker-maven-download confluent kafka-avro-serializer "$CONFLUENT_VERSION" c335c87e25ae347086631092a07d62bd && \ + docker-maven-download confluent kafka-schema-serializer "$CONFLUENT_VERSION" 56c7911fa0561ed839fa8d9c491cc5f4 && \ + docker-maven-download confluent kafka-schema-registry-client "$CONFLUENT_VERSION" bac9144955be1c0c371e6654f6572a35 && \ + docker-maven-download confluent kafka-schema-converter "$CONFLUENT_VERSION" da55aa8de34c16dff1b8537aff958fe2 && \ + docker-maven-download confluent common-config "$CONFLUENT_VERSION" 03052d98b8ff2c72f5f57b45c00becb4 && \ + docker-maven-download confluent common-utils "$CONFLUENT_VERSION" 2ea73bcfa8c0c719d150bfacdd419ae5 && \ + docker-maven-download central org/apache/avro avro "$AVRO_VERSION" 21fa3115ff1dc131ca6432bc73927fa5 && \ + docker-maven-download central com/google/guava guava "$GUAVA_VERSION" 7b7d80d99af4181db55b00dad50a91bb && \ + docker-maven-download central com/google/guava failureaccess "$GUAVA_FAILURE_ACCESS_VERSION" 3f75955b49b6758fd6d1e1bd9bf777b3 CMD ["/entrypoint-wrap.sh"] diff --git a/docker/connect/debezium-mysql.json b/docker/connect/debezium-mysql.json index 7f14e27..b5643b7 100644 --- a/docker/connect/debezium-mysql.json +++ b/docker/connect/debezium-mysql.json @@ -11,27 +11,24 @@ "database.password": "root", "database.server.id": "100000", "database.server.name": "go_api_demo_db", - "database.include.list": "go-api-demo", + "database.include.list": "go_api_demo", "database.history.kafka.bootstrap.servers": "go-api-demo-kafka:9092", - "database.history.kafka.topic": "schema-changes.go-api-demo", + "database.history.kafka.topic": "mysql.database_history.go_api_demo", "database.allowPublicKeyRetrieval":"true", + "topic.prefix": "mysql", + "topic.creation.default.replication.factor": 1, "topic.creation.default.partitions": 1, "topic.creation.default.cleanup.policy": "compact", "topic.creation.default.compression.type": "lz4", - "topic.creation.groups": "users", - - "topic.creation.users.include": "go_api_demo_db\\.go-api-demo\\.users", - "topic.creation.users.replication.factor": 1, - "topic.creation.users.partitions": 2, - "topic.creation.users.cleanup.policy": "compact", - "topic.creation.users.compression.type": "producer", - "key.converter": "io.confluent.connect.avro.AvroConverter", "value.converter": "io.confluent.connect.avro.AvroConverter", "key.converter.schema.registry.url": "http://go-api-demo-schema-registry:8081", - "value.converter.schema.registry.url": "http://go-api-demo-schema-registry:8081" + "value.converter.schema.registry.url": "http://go-api-demo-schema-registry:8081", + + "schema.history.internal.kafka.bootstrap.servers":"go-api-demo-kafka:9092", + "schema.history.internal.kafka.topic":"mysql.schema_history.go_api_demo" } } diff --git a/docker/connect/entrypoint-wrap.sh b/docker/connect/entrypoint-wrap.sh index 77f1daa..4b7223d 100755 --- a/docker/connect/entrypoint-wrap.sh +++ b/docker/connect/entrypoint-wrap.sh @@ -4,6 +4,16 @@ bash -c ' uri=http://go-api-demo-connect:8083/connectors text_break="\n=============\n" +domain=http://go-api-demo-schema-registry:8081 + +echo -e "\n${text_break}Waiting for Schema Registry to start listening on ${domain}${text_break}" + +while [ $(curl -s -o /dev/null -w %{http_code} ${domain}) -ne 200 ] ; do + echo -e "\n${text_break}$(date) Schema Registry listener HTTP state: ${http_code}" \ + $(curl -s -o /dev/null -w %{http_code} ${domain})" (waiting for 200)${text_break}" + sleep 5 +done + echo -e "\n${text_break}Waiting for Kafka Connect to start listening on ${uri}${text_break}" while [ $(curl -s -o /dev/null -w %{http_code} ${uri}) -ne 200 ] ; do diff --git a/docker/dev/docker-compose.yml b/docker/dev/docker-compose.yml index 6f182fb..170543f 100644 --- a/docker/dev/docker-compose.yml +++ b/docker/dev/docker-compose.yml @@ -1,38 +1,28 @@ -version: '3' - services: go-api-demo-db: container_name: go-api-demo-db - image: mysql:8 + image: mysql:9.1 ports: - "3306:3306" environment: PS1: "\\u@\\h:\\w\\$$ " MYSQL_ROOT_PASSWORD: "root" - MYSQL_DATABASE: "go-api-demo" + MYSQL_DATABASE: "go_api_demo" MYSQL_USER: "user" MYSQL_PASSWORD: "password" go-api-demo-prometheus: container_name: go-api-demo-prometheus - image: prom/prometheus:v2.31.1 + image: prom/prometheus:v3.0.1 + restart: always volumes: - - ../prometheus:/etc/prometheus - command: - - '--config.file=/etc/prometheus/prometheus.yml' - - '--storage.tsdb.path=/prometheus' - - '--web.console.libraries=/etc/prometheus/console_libraries' - - '--web.console.templates=/etc/prometheus/consoles' - - '--storage.tsdb.retention.time=200h' - - '--web.enable-lifecycle' + - ../prometheus/prometheus.yaml:/etc/prometheus/prometheus.yml ports: - "9090:9090" - labels: - org.label-schema.group: "monitoring" go-api-demo-grafana: container_name: go-api-demo-grafana - image: grafana/grafana:8.3.2 + image: grafana/grafana:11.3.1 volumes: - ../grafana/config/datasource.yml:/etc/grafana/provisioning/datasources/datasource.yaml - ../grafana/config/dashboards.yml:/etc/grafana/provisioning/dashboards/dashboards.yaml @@ -41,16 +31,35 @@ services: ports: - "3456:3000" + go-api-demo-otel-collector: + container_name: go-api-demo-otel-collector + image: otel/opentelemetry-collector:0.114.0 + restart: always + command: ["--config=/etc/otel-collector-config.yaml", "${OTELCOL_ARGS}"] + volumes: + - ../otel/otel-collector-config.yml:/etc/otel-collector-config.yaml + ports: + - "1888:1888" # pprof extension + - "8888:8888" # Prometheus metrics exposed by the collector + - "8889:8889" # Prometheus exporter metrics + - "13133:13133" # health_check extension + - "4317:4317" # OTLP gRPC receiver + - "55679:55679" # zpages extension + depends_on: + - go-api-demo-jaeger + go-api-demo-jaeger: container_name: go-api-demo-jaeger - image: jaegertracing/all-in-one:1.29 + image: jaegertracing/all-in-one:1.63.0 + restart: always ports: - - "6831:6831/udp" - "16686:16686" + - "14268" + - "14250" go-api-demo-zookeeper: container_name: go-api-demo-zookeeper - image: debezium/zookeeper:1.7 + image: debezium/zookeeper:3.0.0.Final ports: - "2181:2181" - "2888:2888" @@ -58,7 +67,7 @@ services: go-api-demo-kafka: container_name: go-api-demo-kafka - image: debezium/kafka:1.7 + image: debezium/kafka:3.0.0.Final ports: - "9092:9092" environment: @@ -68,6 +77,7 @@ services: go-api-demo-connect: container_name: go-api-demo-connect + image: debezium/connect:3.0.0.Final build: context: ../../ dockerfile: docker/connect/Dockerfile @@ -76,9 +86,9 @@ services: environment: - BOOTSTRAP_SERVERS=go-api-demo-kafka:9092 - GROUP_ID=1 - - CONFIG_STORAGE_TOPIC=go_api_demo_configs - - OFFSET_STORAGE_TOPIC=go_api_demo_offsets - - STATUS_STORAGE_TOPIC=go_api_demo_statuses + - CONFIG_STORAGE_TOPIC=mysql.go_api_demo.configs + - OFFSET_STORAGE_TOPIC=mysql.go_api_demo.offsets + - STATUS_STORAGE_TOPIC=mysql.go_api_demo.statuses - INTERNAL_KEY_CONVERTER=org.apache.kafka.connect.json.JsonConverter - INTERNAL_VALUE_CONVERTER=org.apache.kafka.connect.json.JsonConverter depends_on: @@ -88,6 +98,7 @@ services: go-api-demo-kowl: container_name: go-api-demo-kowl image: quay.io/cloudhut/kowl:master + restart: always ports: - "8080:8080" environment: @@ -101,17 +112,18 @@ services: go-api-demo-redis: container_name: go-api-demo-redis command: redis-server --requirepass pass - image: redis:6.2 + image: redis:7.4 ports: - "6379:6379" go-api-demo-elasticsearch: container_name: go-api-demo-elastic - image: docker.elastic.co/elasticsearch/elasticsearch:7.16.1 + image: docker.elastic.co/elasticsearch/elasticsearch:8.16.1 environment: - discovery.type=single-node - bootstrap.memory_lock=true - "ES_JAVA_OPTS=-Xms512m -Xmx512m" + - xpack.security.enabled=false ulimits: memlock: soft: -1 @@ -122,6 +134,7 @@ services: go-api-demo-schema-registry: container_name: go-api-demo-schema-registry + image: confluentinc/cp-schema-registry:7.7.1 build: context: ../../ dockerfile: docker/schema/Dockerfile diff --git a/docker/grafana/config/datasource.yml b/docker/grafana/config/datasource.yml index c7ab1d6..f17b45e 100644 --- a/docker/grafana/config/datasource.yml +++ b/docker/grafana/config/datasource.yml @@ -5,4 +5,4 @@ datasources: url: http://go-api-demo-prometheus:9090 isDefault: true access: proxy - editable: true \ No newline at end of file + editable: true diff --git a/docker/grafana/dashboards/http_requests.json b/docker/grafana/dashboards/user.json similarity index 60% rename from docker/grafana/dashboards/http_requests.json rename to docker/grafana/dashboards/user.json index a3985a6..c28a2c4 100644 --- a/docker/grafana/dashboards/http_requests.json +++ b/docker/grafana/dashboards/user.json @@ -3,7 +3,10 @@ "list": [ { "builtIn": 1, - "datasource": "-- Grafana --", + "datasource": { + "type": "datasource", + "uid": "grafana" + }, "enable": true, "hide": true, "iconColor": "rgba(0, 211, 255, 1)", @@ -20,23 +23,29 @@ }, "editable": true, "fiscalYearStartMonth": 0, - "gnetId": null, "graphTooltip": 0, - "id": 2, + "id": 9, "links": [], "liveNow": false, "panels": [ { - "datasource": null, + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 0, "gradientMode": "none", @@ -45,11 +54,12 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "smooth", "lineStyle": { "fill": "solid" }, - "lineWidth": 1, + "lineWidth": 2, "pointSize": 5, "scaleDistribution": { "type": "linear" @@ -66,6 +76,7 @@ }, "decimals": 0, "mappings": [], + "min": 0, "thresholds": { "mode": "absolute", "steps": [ @@ -88,22 +99,28 @@ "x": 0, "y": 0 }, - "id": 7, + "id": 17, "maxDataPoints": 500, "options": { "legend": { "calcs": [], - "displayMode": "hidden", - "placement": "bottom" + "displayMode": "list", + "placement": "bottom", + "showLegend": false }, "tooltip": { - "mode": "single" + "mode": "single", + "sort": "none" } }, "targets": [ { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, "exemplar": true, - "expr": "rate(http_request_duration_seconds_count{method=\"GET\",route=\"/user\",code=\"200\"}[1m])", + "expr": "sum without (net_host_name,http_status_code) (rate(http_server_duration_milliseconds_count{http_method=\"GET\", http_route=\"/user\"}[1m]))", "interval": "", "legendFormat": "", "refId": "A" @@ -113,10 +130,7 @@ "type": "timeseries" }, { - "cards": { - "cardPadding": null, - "cardRound": null - }, + "cards": {}, "color": { "cardColor": "#b4ff00", "colorScale": "sqrt", @@ -125,7 +139,26 @@ "mode": "opacity" }, "dataFormat": "tsbuckets", - "datasource": null, + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + }, + "fieldMinMax": false + }, + "overrides": [] + }, "gridPos": { "h": 7, "w": 6, @@ -135,18 +168,65 @@ "heatmap": {}, "hideZeroBuckets": true, "highlightCards": true, - "id": 5, + "id": 21, "legend": { "show": false }, "maxDataPoints": 50, + "options": { + "calculate": false, + "calculation": {}, + "cellGap": 1, + "cellValues": { + "decimals": -2 + }, + "color": { + "exponent": 0.5, + "fill": "#b4ff00", + "mode": "opacity", + "reverse": false, + "scale": "exponential", + "scheme": "Oranges", + "steps": 128 + }, + "exemplars": { + "color": "rgba(255,0,255,0.7)" + }, + "filterValues": { + "le": 0 + }, + "legend": { + "show": false + }, + "rowsFrame": { + "layout": "ge" + }, + "showValue": "never", + "tooltip": { + "mode": "single", + "showColorScale": false, + "yHistogram": false + }, + "yAxis": { + "axisPlacement": "left", + "decimals": 0, + "reverse": false, + "unit": "ms" + } + }, + "pluginVersion": "11.2.2", "reverseYBuckets": false, "targets": [ { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, "exemplar": true, - "expr": "sum(rate(http_request_duration_seconds_bucket{method=\"GET\",route=\"/user\",code=\"200\"}[$__interval])) by (le)", + "expr": "sum(rate(http_server_duration_milliseconds_bucket{http_method=\"GET\",http_route=\"/user\",http_status_code=\"200\"}[$__interval])) by (le)", "format": "heatmap", "interval": "", + "intervalFactor": 1, "legendFormat": "{{le}}", "refId": "A" } @@ -160,35 +240,43 @@ "xAxis": { "show": true }, - "xBucketNumber": null, - "xBucketSize": null, "yAxis": { "decimals": 0, - "format": "s", + "format": "ms", "logBase": 1, - "max": null, - "min": null, - "show": true, - "splitFactor": null + "show": true }, - "yBucketBound": "auto", - "yBucketNumber": null, - "yBucketSize": null + "yBucketBound": "auto" }, { - "cards": { - "cardPadding": null, - "cardRound": null - }, + "cards": {}, "color": { - "cardColor": "rgba(247, 4, 23, 1)", + "cardColor": "#f80320", "colorScale": "sqrt", "colorScheme": "interpolateOranges", "exponent": 0.5, "mode": "opacity" }, "dataFormat": "tsbuckets", - "datasource": null, + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, "gridPos": { "h": 7, "w": 6, @@ -198,23 +286,68 @@ "heatmap": {}, "hideZeroBuckets": true, "highlightCards": true, - "id": 3, + "id": 22, "legend": { "show": false }, "maxDataPoints": 50, + "options": { + "calculate": false, + "calculation": {}, + "cellGap": 1, + "cellValues": {}, + "color": { + "exponent": 0.5, + "fill": "#f80320", + "mode": "opacity", + "reverse": false, + "scale": "exponential", + "scheme": "Oranges", + "steps": 128 + }, + "exemplars": { + "color": "rgba(255,0,255,0.7)" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": false + }, + "rowsFrame": { + "layout": "ge" + }, + "showValue": "never", + "tooltip": { + "mode": "single", + "showColorScale": false, + "yHistogram": false + }, + "yAxis": { + "axisPlacement": "left", + "decimals": 0, + "reverse": false, + "unit": "ms" + } + }, + "pluginVersion": "11.2.2", "reverseYBuckets": false, "targets": [ { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, "exemplar": true, - "expr": "sum(rate(http_request_duration_seconds_bucket{method=\"GET\",route=\"/user\",code=\"500\"}[$__interval])) by (le)", + "expr": "sum(rate(http_server_duration_milliseconds_bucket{http_method=\"GET\",http_route=\"/user\",http_status_code=~\"5.+\"}[$__interval])) by (le)", "format": "heatmap", "interval": "", + "intervalFactor": 1, "legendFormat": "{{le}}", "refId": "A" } ], - "title": "GET /user 500", + "title": "GET /user 5xx", "tooltip": { "show": true, "showHistogram": false @@ -223,32 +356,32 @@ "xAxis": { "show": true }, - "xBucketNumber": null, - "xBucketSize": null, "yAxis": { "decimals": 0, - "format": "s", + "format": "ms", "logBase": 1, - "max": null, - "min": null, - "show": true, - "splitFactor": null + "show": true }, - "yBucketBound": "auto", - "yBucketNumber": null, - "yBucketSize": null + "yBucketBound": "auto" }, { - "datasource": null, + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 0, "gradientMode": "none", @@ -257,11 +390,12 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "smooth", "lineStyle": { "fill": "solid" }, - "lineWidth": 1, + "lineWidth": 2, "pointSize": 5, "scaleDistribution": { "type": "linear" @@ -278,6 +412,7 @@ }, "decimals": 0, "mappings": [], + "min": 0, "thresholds": { "mode": "absolute", "steps": [ @@ -287,15 +422,15 @@ }, { "color": "#EAB839", - "value": 0.5 + "value": 500 }, { "color": "red", - "value": 1 + "value": 1000 } ] }, - "unit": "s" + "unit": "ms" }, "overrides": [] }, @@ -305,22 +440,28 @@ "x": 18, "y": 0 }, - "id": 16, + "id": 23, "maxDataPoints": 500, "options": { "legend": { "calcs": [], - "displayMode": "hidden", - "placement": "bottom" + "displayMode": "list", + "placement": "bottom", + "showLegend": false }, "tooltip": { - "mode": "single" + "mode": "single", + "sort": "none" } }, "targets": [ { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, "exemplar": true, - "expr": "histogram_quantile(0.99,\n sum(rate(\n http_request_duration_seconds_bucket{method=\"GET\"}[1m]\n )) by (method,le)\n)", + "expr": "histogram_quantile(0.99,\n sum(rate(\n http_server_duration_milliseconds_bucket{http_method=\"GET\"}[1m]\n )) by (http_method,le)\n)", "interval": "", "legendFormat": "", "refId": "A" @@ -330,16 +471,23 @@ "type": "timeseries" }, { - "datasource": null, + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -348,6 +496,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "smooth", "lineStyle": { "fill": "solid" @@ -369,6 +518,7 @@ }, "decimals": 0, "mappings": [], + "min": 0, "thresholds": { "mode": "absolute", "steps": [ @@ -391,22 +541,28 @@ "x": 0, "y": 7 }, - "id": 13, + "id": 25, "maxDataPoints": 500, "options": { "legend": { "calcs": [], - "displayMode": "hidden", - "placement": "bottom" + "displayMode": "list", + "placement": "bottom", + "showLegend": false }, "tooltip": { - "mode": "single" + "mode": "single", + "sort": "none" } }, "targets": [ { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, "exemplar": true, - "expr": "rate(http_request_duration_seconds_count{method=\"POST\",route=\"/user\",code=\"201\"}[1m])", + "expr": "sum without (net_host_name) (rate(http_server_duration_milliseconds_count{http_method=\"POST\", http_route=\"/user\"}[1m]))", "interval": "", "legendFormat": "", "refId": "A" @@ -416,20 +572,34 @@ "type": "timeseries" }, { - "cards": { - "cardPadding": null, - "cardRound": null - }, + "cards": {}, "color": { "cardColor": "#b4ff00", "colorScale": "sqrt", "colorScheme": "interpolateOranges", "exponent": 0.5, - "min": null, "mode": "opacity" }, "dataFormat": "tsbuckets", - "datasource": null, + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, "gridPos": { "h": 7, "w": 6, @@ -439,23 +609,67 @@ "heatmap": {}, "hideZeroBuckets": true, "highlightCards": true, - "id": 14, + "id": 27, "legend": { "show": false }, "maxDataPoints": 50, + "options": { + "calculate": false, + "calculation": {}, + "cellGap": 1, + "cellValues": {}, + "color": { + "exponent": 0.5, + "fill": "#b4ff00", + "mode": "opacity", + "reverse": false, + "scale": "exponential", + "scheme": "Oranges", + "steps": 128 + }, + "exemplars": { + "color": "rgba(255,0,255,0.7)" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": false + }, + "rowsFrame": { + "layout": "ge" + }, + "showValue": "never", + "tooltip": { + "mode": "single", + "showColorScale": false, + "yHistogram": false + }, + "yAxis": { + "axisPlacement": "left", + "decimals": 0, + "reverse": false, + "unit": "ms" + } + }, + "pluginVersion": "11.2.2", "reverseYBuckets": false, "targets": [ { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, "exemplar": true, - "expr": "sum(rate(http_request_duration_seconds_bucket{method=\"POST\",route=\"/user\",code=\"201\"}[$__interval])) by (le)", + "expr": "sum(rate(http_server_duration_milliseconds_bucket{http_method=\"POST\",http_route=\"/user\",http_status_code=\"201\"}[$__interval])) by (le)", "format": "heatmap", "interval": "", "legendFormat": "{{le}}", "refId": "A" } ], - "title": "POST /user 200", + "title": "POST /user 201", "tooltip": { "show": true, "showHistogram": false @@ -464,32 +678,147 @@ "xAxis": { "show": true }, - "xBucketNumber": null, - "xBucketSize": null, "yAxis": { "decimals": 0, - "format": "s", + "format": "ms", "logBase": 1, - "max": null, - "min": null, + "show": true + }, + "yBucketBound": "auto" + }, + { + "cards": {}, + "color": { + "cardColor": "rgba(247, 4, 23, 1)", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "opacity" + }, + "dataFormat": "tsbuckets", + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + } + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 7 + }, + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "id": 29, + "legend": { + "show": false + }, + "maxDataPoints": 50, + "options": { + "calculate": false, + "calculation": {}, + "cellGap": 1, + "cellValues": {}, + "color": { + "exponent": 0.5, + "fill": "rgba(247, 4, 23, 1)", + "mode": "opacity", + "reverse": false, + "scale": "exponential", + "scheme": "Oranges", + "steps": 128 + }, + "exemplars": { + "color": "rgba(255,0,255,0.7)" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": false + }, + "rowsFrame": { + "layout": "ge" + }, + "showValue": "never", + "tooltip": { + "mode": "single", + "showColorScale": false, + "yHistogram": false + }, + "yAxis": { + "axisPlacement": "left", + "decimals": 0, + "reverse": false, + "unit": "ms" + } + }, + "pluginVersion": "11.2.2", + "reverseYBuckets": false, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "exemplar": true, + "expr": "sum(rate(http_server_duration_milliseconds_bucket{http_method=\"POST\",http_route=\"/user\",http_status_code=~\"5.+\"}[$__interval])) by (le)", + "format": "heatmap", + "interval": "", + "legendFormat": "{{le}}", + "refId": "A" + } + ], + "title": "POST /user 5xx", + "tooltip": { "show": true, - "splitFactor": null + "showHistogram": false + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "yAxis": { + "decimals": 0, + "format": "ms", + "logBase": 1, + "show": true }, - "yBucketBound": "auto", - "yBucketNumber": null, - "yBucketSize": null + "yBucketBound": "auto" }, { - "datasource": null, + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 0, "gradientMode": "none", @@ -498,6 +827,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "smooth", "lineStyle": { "fill": "solid" @@ -519,6 +849,7 @@ }, "decimals": 0, "mappings": [], + "min": 0, "thresholds": { "mode": "absolute", "steps": [ @@ -528,40 +859,46 @@ }, { "color": "#EAB839", - "value": 0.5 + "value": 500 }, { "color": "red", - "value": 1 + "value": 1000 } ] }, - "unit": "s" + "unit": "ms" }, "overrides": [] }, "gridPos": { "h": 7, "w": 6, - "x": 12, + "x": 18, "y": 7 }, - "id": 12, + "id": 31, "maxDataPoints": 500, "options": { "legend": { "calcs": [], - "displayMode": "hidden", - "placement": "bottom" + "displayMode": "list", + "placement": "bottom", + "showLegend": false }, "tooltip": { - "mode": "single" + "mode": "single", + "sort": "none" } }, "targets": [ { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, "exemplar": true, - "expr": "histogram_quantile(0.99,\n sum(rate(\n http_request_duration_seconds_bucket{method=\"POST\"}[$__interval]\n )) by (method,le)\n)", + "expr": "histogram_quantile(0.99,\n sum(rate(\n http_server_duration_milliseconds_bucket{http_method=\"POST\"}[$__interval]\n )) by (http_method,le)\n)", "interval": "", "legendFormat": "", "refId": "A" @@ -571,79 +908,23 @@ "type": "timeseries" }, { - "cards": { - "cardPadding": null, - "cardRound": null - }, - "color": { - "cardColor": "rgba(247, 4, 23, 1)", - "colorScale": "sqrt", - "colorScheme": "interpolateOranges", - "exponent": 0.5, - "mode": "opacity" + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" }, - "dataFormat": "tsbuckets", - "datasource": null, - "gridPos": { - "h": 7, - "w": 6, - "x": 18, - "y": 7 - }, - "heatmap": {}, - "hideZeroBuckets": true, - "highlightCards": true, - "id": 22, - "legend": { - "show": false - }, - "maxDataPoints": 50, - "reverseYBuckets": false, - "targets": [ - { - "exemplar": true, - "expr": "sum(rate(http_request_duration_seconds_bucket{method=\"POST\",route=\"/user\",code=\"500\"}[$__interval])) by (le)", - "format": "heatmap", - "interval": "", - "legendFormat": "{{le}}", - "refId": "A" - } - ], - "title": "POST /user 500", - "tooltip": { - "show": true, - "showHistogram": false - }, - "type": "heatmap", - "xAxis": { - "show": true - }, - "xBucketNumber": null, - "xBucketSize": null, - "yAxis": { - "decimals": 0, - "format": "s", - "logBase": 1, - "max": null, - "min": null, - "show": true, - "splitFactor": null - }, - "yBucketBound": "auto", - "yBucketNumber": null, - "yBucketSize": null - }, - { - "datasource": null, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -652,6 +933,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "smooth", "lineStyle": { "fill": "solid" @@ -726,30 +1008,40 @@ "x": 0, "y": 14 }, - "id": 17, + "id": 33, "maxDataPoints": 500, "options": { "legend": { "calcs": [], - "displayMode": "hidden", - "placement": "bottom" + "displayMode": "list", + "placement": "bottom", + "showLegend": false }, "tooltip": { - "mode": "single" + "mode": "single", + "sort": "none" } }, "targets": [ { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, "exemplar": false, - "expr": "rate(consumer_messages_total{processor=\"cache\"}[$__interval])", + "expr": "sum by (destination) (rate(kafka_consumer_messages_total{destination=\"cache\"}[$__interval]))", "instant": false, "interval": "", "legendFormat": "{{processor}}", "refId": "A" }, { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, "exemplar": true, - "expr": "sum by (processor) (rate(consumer_messages_total{processor=\"search\"}[$__interval]))", + "expr": "sum by (destination) (rate(kafka_consumer_messages_total{destination=\"search\"}[$__interval]))", "hide": false, "interval": "", "legendFormat": "{{processor}}", @@ -760,16 +1052,23 @@ "type": "timeseries" }, { - "datasource": null, + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 0, "gradientMode": "none", @@ -778,6 +1077,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "smooth", "lineStyle": { "fill": "solid" @@ -826,7 +1126,7 @@ { "matcher": { "id": "byName", - "options": "{consumer=\"user-consumer-cache-group-id-0\", instance=\"host.docker.internal:3000\", job=\"go-api-demo\", processor=\"cache\", type=\"user\"}" + "options": "{destination=\"cache\"}" }, "properties": [ { @@ -841,7 +1141,7 @@ { "matcher": { "id": "byName", - "options": "{processor=\"search\"}" + "options": "{destination=\"search\"}" }, "properties": [ { @@ -861,29 +1161,39 @@ "x": 6, "y": 14 }, - "id": 24, + "id": 35, "maxDataPoints": 500, "options": { "legend": { "calcs": [], - "displayMode": "hidden", - "placement": "bottom" + "displayMode": "list", + "placement": "bottom", + "showLegend": false }, "tooltip": { - "mode": "single" + "mode": "single", + "sort": "none" } }, "targets": [ { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, "exemplar": true, - "expr": "(consumer_queue_length{processor=\"cache\"}/consumer_queue_capacity{processor=\"cache\"})*100", + "expr": "avg by (destination)((kafka_consumer_queue_length{destination=\"cache\"}/kafka_consumer_queue_capacity{destination=\"cache\"})*100)", "interval": "", "legendFormat": "", "refId": "A" }, { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, "exemplar": true, - "expr": "avg by (processor)((consumer_queue_length{processor=\"search\"}/consumer_queue_capacity{processor=\"search\"})*100)", + "expr": "avg by (destination)((kafka_consumer_queue_length{destination=\"search\"}/kafka_consumer_queue_capacity{destination=\"search\"})*100)", "hide": false, "interval": "", "legendFormat": "", @@ -894,16 +1204,23 @@ "type": "timeseries" }, { - "datasource": null, + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -912,6 +1229,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "smooth", "lineStyle": { "fill": "solid" @@ -951,7 +1269,7 @@ { "matcher": { "id": "byName", - "options": "consumer_lag{consumer=\"user-consumer-cache-group-id-0\", instance=\"host.docker.internal:3000\", job=\"go-api-demo\", processor=\"cache\", type=\"user\"}" + "options": "sum(kafka_consumer_lag{destination=\"cache\"})" }, "properties": [ { @@ -966,7 +1284,7 @@ { "matcher": { "id": "byName", - "options": "sum(consumer_lag{processor=\"search\"})" + "options": "sum(kafka_consumer_lag{destination=\"search\"})" }, "properties": [ { @@ -986,29 +1304,39 @@ "x": 12, "y": 14 }, - "id": 25, + "id": 37, "maxDataPoints": 500, "options": { "legend": { "calcs": [], - "displayMode": "hidden", - "placement": "bottom" + "displayMode": "list", + "placement": "bottom", + "showLegend": false }, "tooltip": { - "mode": "single" + "mode": "single", + "sort": "none" } }, "targets": [ { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, "exemplar": true, - "expr": "consumer_lag{processor=\"cache\"}", + "expr": "sum(kafka_consumer_lag{destination=\"cache\"})", "interval": "", "legendFormat": "", "refId": "A" }, { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, "exemplar": true, - "expr": "sum(consumer_lag{processor=\"search\"})", + "expr": "sum(kafka_consumer_lag{destination=\"search\"})", "hide": false, "interval": "", "legendFormat": "", @@ -1020,8 +1348,7 @@ } ], "refresh": "5s", - "schemaVersion": 31, - "style": "dark", + "schemaVersion": 39, "tags": [], "templating": { "list": [] @@ -1033,6 +1360,7 @@ "timepicker": {}, "timezone": "", "title": "user", - "uid": "gzDHg9W7z", - "version": 1 + "uid": "Ml6DaygHl", + "version": 2, + "weekStart": "" } \ No newline at end of file diff --git a/docker/otel/otel-collector-config.yml b/docker/otel/otel-collector-config.yml new file mode 100644 index 0000000..b93de4e --- /dev/null +++ b/docker/otel/otel-collector-config.yml @@ -0,0 +1,38 @@ +receivers: + otlp: + protocols: + grpc: + endpoint: 0.0.0.0:4317 + +exporters: + prometheus: + endpoint: "0.0.0.0:8889" + + debug: + + otlp: + endpoint: go-api-demo-jaeger:4317 + tls: + insecure: true + +processors: + batch: + +extensions: + health_check: + pprof: + endpoint: :1888 + zpages: + endpoint: :55679 + +service: + extensions: [pprof, zpages, health_check] + pipelines: + traces: + receivers: [otlp] + processors: [batch] + exporters: [debug, otlp] + metrics: + receivers: [otlp] + processors: [batch] + exporters: [debug, prometheus] \ No newline at end of file diff --git a/docker/prometheus/prometheus.yaml b/docker/prometheus/prometheus.yaml new file mode 100644 index 0000000..858357b --- /dev/null +++ b/docker/prometheus/prometheus.yaml @@ -0,0 +1,6 @@ +scrape_configs: + - job_name: 'otel-collector' + scrape_interval: 5s + static_configs: + - targets: ['go-api-demo-otel-collector:8889'] + - targets: ['go-api-demo-otel-collector:8888'] \ No newline at end of file diff --git a/docker/prometheus/prometheus.yml b/docker/prometheus/prometheus.yml deleted file mode 100644 index 3c6579e..0000000 --- a/docker/prometheus/prometheus.yml +++ /dev/null @@ -1,6 +0,0 @@ -scrape_configs: - - job_name: go-api-demo - scrape_interval: 5s - static_configs: - - targets: - - host.docker.internal:3000 diff --git a/docker/schema/Dockerfile b/docker/schema/Dockerfile index ee36cdf..5786177 100644 --- a/docker/schema/Dockerfile +++ b/docker/schema/Dockerfile @@ -1,4 +1,4 @@ -FROM confluentinc/cp-schema-registry +FROM confluentinc/cp-schema-registry:7.7.2 COPY docker/schema/entrypoint-wrap.sh /entrypoint-wrap.sh COPY docker/schema/users-value.json /users-value.json diff --git a/docker/schema/entrypoint-wrap.sh b/docker/schema/entrypoint-wrap.sh index eb2057f..bc23634 100755 --- a/docker/schema/entrypoint-wrap.sh +++ b/docker/schema/entrypoint-wrap.sh @@ -2,7 +2,7 @@ bash -c ' domain=http://go-api-demo-schema-registry:8081 -endpoint=/subjects/go_api_demo_db.go-api-demo.users-value/versions +endpoint=/subjects/mysql.go_api_demo.users-value/versions text_break="\n=============\n" diff --git a/docker/schema/users-value.json b/docker/schema/users-value.json index 2944156..ecd28a5 100644 --- a/docker/schema/users-value.json +++ b/docker/schema/users-value.json @@ -2,192 +2,227 @@ "schema": "{ \"type\": \"record\", \"name\": \"Envelope\", - \"namespace\": \"go_api_demo_db.go_api_demo.users\", + \"namespace\": \"mysql.go_api_demo.users\", \"fields\": [ - { - \"name\": \"before\", - \"type\": [ - \"null\", - { - \"type\": \"record\", - \"name\": \"Value\", - \"fields\": [ - { - \"name\": \"id\", - \"type\": \"string\" - }, - { - \"name\": \"first_name\", - \"type\": \"string\" - }, - { - \"name\": \"last_name\", - \"type\": \"string\" - }, - { - \"name\": \"created_at\", - \"type\": { - \"type\": \"long\", - \"connect.version\": 1, - \"connect.name\": \"io.debezium.time.Timestamp\" + { + \"name\": \"before\", + \"type\": [ + \"null\", + { + \"type\": \"record\", + \"name\": \"Value\", + \"fields\": [ + { + \"name\": \"id\", + \"type\": \"string\" + }, + { + \"name\": \"first_name\", + \"type\": \"string\" + }, + { + \"name\": \"last_name\", + \"type\": \"string\" + }, + { + \"name\": \"created_at\", + \"type\": { + \"type\": \"long\", + \"connect.version\": 1, + \"connect.name\": \"io.debezium.time.Timestamp\" + } + } + ], + \"connect.name\": \"mysql.go_api_demo.users.Value\" } - } ], - \"connect.name\": \"go_api_demo_db.go_api_demo.users.Value\" - } - ], - \"default\": null - }, - { - \"name\": \"after\", - \"type\": [ - \"null\", - \"Value\" - ], - \"default\": null - }, - { - \"name\": \"source\", - \"type\": { - \"type\": \"record\", - \"name\": \"Source\", - \"namespace\": \"io.debezium.connector.mysql\", - \"fields\": [ - { - \"name\": \"version\", - \"type\": \"string\" - }, - { - \"name\": \"connector\", - \"type\": \"string\" - }, - { - \"name\": \"name\", - \"type\": \"string\" - }, - { - \"name\": \"ts_ms\", - \"type\": \"long\" - }, - { - \"name\": \"snapshot\", - \"type\": [ - { - \"type\": \"string\", - \"connect.version\": 1, - \"connect.parameters\": { - \"allowed\": \"true,last,false\" - }, - \"connect.default\": \"false\", - \"connect.name\": \"io.debezium.data.Enum\" - }, - \"null\" - ], - \"default\": \"false\" - }, - { - \"name\": \"db\", - \"type\": \"string\" - }, - { - \"name\": \"sequence\", - \"type\": [ + \"default\": null + }, + { + \"name\": \"after\", + \"type\": [ \"null\", - \"string\" - ], - \"default\": null - }, - { - \"name\": \"table\", - \"type\": [ + \"Value\" + ], + \"default\": null + }, + { + \"name\": \"source\", + \"type\": { + \"type\": \"record\", + \"name\": \"Source\", + \"namespace\": \"io.debezium.connector.mysql\", + \"fields\": [ + { + \"name\": \"version\", + \"type\": \"string\" + }, + { + \"name\": \"connector\", + \"type\": \"string\" + }, + { + \"name\": \"name\", + \"type\": \"string\" + }, + { + \"name\": \"ts_ms\", + \"type\": \"long\" + }, + { + \"name\": \"snapshot\", + \"type\": [ + { + \"type\": \"string\", + \"connect.version\": 1, + \"connect.parameters\": { + \"allowed\": \"true,last,false,incremental\" + }, + \"connect.default\": \"false\", + \"connect.name\": \"io.debezium.data.Enum\" + }, + \"null\" + ], + \"default\": \"false\" + }, + { + \"name\": \"db\", + \"type\": \"string\" + }, + { + \"name\": \"sequence\", + \"type\": [ + \"null\", + \"string\" + ], + \"default\": null + }, + { + \"name\": \"ts_us\", + \"type\": [ + \"null\", + \"long\" + ], + \"default\": null + }, + { + \"name\": \"ts_ns\", + \"type\": [ + \"null\", + \"long\" + ], + \"default\": null + }, + { + \"name\": \"table\", + \"type\": [ + \"null\", + \"string\" + ], + \"default\": null + }, + { + \"name\": \"server_id\", + \"type\": \"long\" + }, + { + \"name\": \"gtid\", + \"type\": [ + \"null\", + \"string\" + ], + \"default\": null + }, + { + \"name\": \"file\", + \"type\": \"string\" + }, + { + \"name\": \"pos\", + \"type\": \"long\" + }, + { + \"name\": \"row\", + \"type\": \"int\" + }, + { + \"name\": \"thread\", + \"type\": [ + \"null\", + \"long\" + ], + \"default\": null + }, + { + \"name\": \"query\", + \"type\": [ + \"null\", + \"string\" + ], + \"default\": null + } + ], + \"connect.name\": \"io.debezium.connector.mysql.Source\" + } + }, + { + \"name\": \"transaction\", + \"type\": [ \"null\", - \"string\" - ], - \"default\": null - }, - { - \"name\": \"server_id\", - \"type\": \"long\" - }, - { - \"name\": \"gtid\", - \"type\": [ + { + \"type\": \"record\", + \"name\": \"block\", + \"namespace\": \"event\", + \"fields\": [ + { + \"name\": \"id\", + \"type\": \"string\" + }, + { + \"name\": \"total_order\", + \"type\": \"long\" + }, + { + \"name\": \"data_collection_order\", + \"type\": \"long\" + } + ], + \"connect.version\": 1, + \"connect.name\": \"event.block\" + } + ], + \"default\": null + }, + { + \"name\": \"op\", + \"type\": \"string\" + }, + { + \"name\": \"ts_ms\", + \"type\": [ \"null\", - \"string\" - ], - \"default\": null - }, - { - \"name\": \"file\", - \"type\": \"string\" - }, - { - \"name\": \"pos\", - \"type\": \"long\" - }, - { - \"name\": \"row\", - \"type\": \"int\" - }, - { - \"name\": \"thread\", - \"type\": [ + \"long\" + ], + \"default\": null + }, + { + \"name\": \"ts_us\", + \"type\": [ \"null\", \"long\" - ], - \"default\": null - }, - { - \"name\": \"query\", - \"type\": [ + ], + \"default\": null + }, + { + \"name\": \"ts_ns\", + \"type\": [ \"null\", - \"string\" - ], - \"default\": null - } - ], - \"connect.name\": \"io.debezium.connector.mysql.Source\" + \"long\" + ], + \"default\": null } - }, - { - \"name\": \"op\", - \"type\": \"string\" - }, - { - \"name\": \"ts_ms\", - \"type\": [ - \"null\", - \"long\" - ], - \"default\": null - }, - { - \"name\": \"transaction\", - \"type\": [ - \"null\", - { - \"type\": \"record\", - \"name\": \"ConnectDefault\", - \"namespace\": \"io.confluent.connect.avro\", - \"fields\": [ - { - \"name\": \"id\", - \"type\": \"string\" - }, - { - \"name\": \"total_order\", - \"type\": \"long\" - }, - { - \"name\": \"data_collection_order\", - \"type\": \"long\" - } - ] - } - ], - \"default\": null - } ], - \"connect.name\": \"go_api_demo_db.go_api_demo.users.Envelope\" - }" + \"connect.version\": 2, + \"connect.name\": \"mysql.go_api_demo.users.Envelope\" +}" } \ No newline at end of file diff --git a/go.mod b/go.mod index 734497b..9c62436 100644 --- a/go.mod +++ b/go.mod @@ -1,71 +1,71 @@ module github.com/bendbennett/go-api-demo -go 1.17 +go 1.23.3 require ( - github.com/elastic/go-elasticsearch/v7 v7.16.0 - github.com/go-playground/locales v0.14.0 - github.com/go-playground/universal-translator v0.18.0 - github.com/go-redis/redis/v8 v8.11.4 - github.com/go-sql-driver/mysql v1.6.0 - github.com/golang-migrate/migrate v3.5.4+incompatible - github.com/google/uuid v1.3.0 - github.com/gorilla/mux v1.8.0 - github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 - github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 - github.com/joho/godotenv v1.4.0 - github.com/linkedin/goavro/v2 v2.10.1 - github.com/luna-duclos/instrumentedsql v1.1.3 - github.com/luna-duclos/instrumentedsql/opentracing v0.0.0-20201103091713-40d03108b6f4 - github.com/mitchellh/mapstructure v1.4.3 - github.com/opentracing-contrib/go-stdlib v1.0.0 - github.com/opentracing/opentracing-go v1.2.0 - github.com/prometheus/client_golang v1.11.0 - github.com/segmentio/kafka-go v0.4.25 - github.com/stretchr/testify v1.7.0 - github.com/uber/jaeger-client-go v2.30.0+incompatible - github.com/uber/jaeger-lib v2.4.1+incompatible - go.uber.org/zap v1.19.1 - golang.org/x/sync v0.0.0-20210220032951-036812b2e83c - google.golang.org/grpc v1.42.0 - google.golang.org/protobuf v1.27.1 + github.com/XSAM/otelsql v0.35.0 + github.com/elastic/go-elasticsearch/v8 v8.16.0 + github.com/go-playground/locales v0.14.1 + github.com/go-playground/universal-translator v0.18.1 + github.com/go-sql-driver/mysql v1.8.1 + github.com/google/uuid v1.6.0 + github.com/gorilla/mux v1.8.1 + github.com/joho/godotenv v1.5.1 + github.com/linkedin/goavro/v2 v2.13.0 + github.com/mitchellh/mapstructure v1.5.0 + github.com/pkg/errors v0.9.1 + github.com/redis/go-redis/v9 v9.7.0 + github.com/segmentio/kafka-go v0.4.47 + github.com/stretchr/testify v1.10.0 + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.57.0 + go.opentelemetry.io/contrib/instrumentation/runtime v0.57.0 + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.32.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.32.0 + go.opentelemetry.io/otel/sdk v1.32.0 + go.opentelemetry.io/otel/sdk/metric v1.32.0 + go.uber.org/zap v1.27.0 + golang.org/x/sync v0.9.0 + google.golang.org/grpc v1.68.0 + google.golang.org/protobuf v1.35.2 gopkg.in/go-playground/validator.v9 v9.31.0 ) require ( - github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect - github.com/Microsoft/go-winio v0.5.1 // indirect - github.com/beorn7/perks v1.0.1 // indirect - github.com/cespare/xxhash/v2 v2.1.2 // indirect - github.com/containerd/containerd v1.4.1 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + go.opentelemetry.io/proto/otlp v1.3.1 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697 // indirect +) + +require ( + filippo.io/edwards25519 v1.1.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect - github.com/docker/distribution v2.7.1+incompatible // indirect - github.com/docker/docker v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible // indirect - github.com/docker/go-connections v0.4.0 // indirect - github.com/docker/go-units v0.4.0 // indirect - github.com/golang/protobuf v1.5.2 // indirect + github.com/docker/docker v27.3.1+incompatible // indirect + github.com/elastic/elastic-transport-go/v8 v8.6.0 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/golang-migrate/migrate/v4 v4.18.1 github.com/golang/snappy v0.0.4 // indirect - github.com/klauspost/compress v1.13.6 // indirect - github.com/leodido/go-urn v1.2.1 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect - github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.0.1 // indirect - github.com/pierrec/lz4 v2.6.1+incompatible // indirect - github.com/pkg/errors v0.9.1 // indirect + github.com/klauspost/compress v1.17.11 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/pierrec/lz4/v4 v4.1.21 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_model v0.2.0 // indirect - github.com/prometheus/common v0.32.1 // indirect - github.com/prometheus/procfs v0.7.3 // indirect - github.com/sirupsen/logrus v1.8.1 // indirect - go.uber.org/atomic v1.9.0 // indirect - go.uber.org/multierr v1.7.0 // indirect - golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect - golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect - golang.org/x/sys v0.0.0-20211210111614-af8b64212486 // indirect - golang.org/x/text v0.3.7 // indirect - google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect - gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0 + go.opentelemetry.io/otel v1.32.0 + go.opentelemetry.io/otel/metric v1.32.0 + go.opentelemetry.io/otel/trace v1.32.0 + go.uber.org/atomic v1.11.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + golang.org/x/net v0.31.0 + golang.org/x/sys v0.27.0 // indirect + golang.org/x/text v0.20.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697 // indirect gopkg.in/go-playground/assert.v1 v1.2.1 // indirect - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 3c3f5ae..853b1d6 100644 --- a/go.sum +++ b/go.sum @@ -1,687 +1,221 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -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.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/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/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= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM= -github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= -github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY= -github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= -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 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= -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.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= -github.com/cespare/xxhash/v2 v2.1.2/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-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-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/containerd/containerd v1.4.1 h1:pASeJT3R3YyVn+94qEPk0SnU1OQ20Jd/T+SPKy9xehY= -github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/XSAM/otelsql v0.35.0 h1:nMdbU/XLmBIB6qZF61uDqy46E0LVA4ZgF/FCNw8Had4= +github.com/XSAM/otelsql v0.35.0/go.mod h1:wO028mnLzmBpstK8XPsoeRLl/kgt417yjAwOGDIptTc= +github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= +github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= +github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= +github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 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/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= -github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= -github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible h1:iWPIG7pWIsCwT6ZtHnTUpoVMnete7O/pzd9HFE3+tn8= -github.com/docker/docker v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= -github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= -github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= -github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 h1:YEetp8/yCZMuEPMUDHG0CW/brkkEp8mzqk2+ODEitlw= -github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= -github.com/elastic/go-elasticsearch/v7 v7.16.0 h1:GHsxDFXIAlhSleXun4kwA89P7kQFADRChqvgOPeYP5A= -github.com/elastic/go-elasticsearch/v7 v7.16.0/go.mod h1:OJ4wdbtDNk5g503kvlHLyErCgQwwzmDtaFC4XyOxXA4= -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.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= -github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= -github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -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-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/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -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-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= -github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= -github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= -github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= -github.com/go-redis/redis/v8 v8.11.4 h1:kHoYkfZP6+pe04aFTnhDH6GDROa5yJdHJVNxV3F46Tg= -github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w= -github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= -github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/dhui/dktest v0.4.3 h1:wquqUxAFdcUgabAVLvSCOKOlag5cIZuaOjYIBOWdsR0= +github.com/dhui/dktest v0.4.3/go.mod h1:zNK8IwktWzQRm6I/l2Wjp7MakiyaFWv4G1hjmodmMTs= +github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/docker/docker v27.3.1+incompatible h1:KttF0XoteNTicmUtBO0L2tP+J7FGRFTjaEF4k6WdhfI= +github.com/docker/docker v27.3.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= +github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/elastic/elastic-transport-go/v8 v8.6.0 h1:Y2S/FBjx1LlCv5m6pWAF2kDJAHoSjSRSJCApolgfthA= +github.com/elastic/elastic-transport-go/v8 v8.6.0/go.mod h1:YLHer5cj0csTzNFXoNQ8qhtGY1GTvSqPnKWKaqQE3Hk= +github.com/elastic/go-elasticsearch/v8 v8.16.0 h1:f7bR+iBz8GTAVhwyFO3hm4ixsz2eMaEy0QroYnXV3jE= +github.com/elastic/go-elasticsearch/v8 v8.16.0/go.mod h1:lGMlgKIbYoRvay3xWBeKahAiJOgmFDsjZC39nmO3H64= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-migrate/migrate v3.5.4+incompatible h1:R7OzwvCJTCgwapPCiX6DyBiu2czIUMDCB118gFTKTUA= -github.com/golang-migrate/migrate v3.5.4+incompatible/go.mod h1:IsVUlFN5puWOmXrqjgGUfIRIbU7mr8oNBE2tyERd9Wk= -github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/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= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -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-migrate/migrate/v4 v4.18.1 h1:JML/k+t4tpHCpQTCAD62Nu43NUFzHY4CV3uAuvHGC+Y= +github.com/golang-migrate/migrate/v4 v4.18.1/go.mod h1:HAX6m3sQgcdO81tdjn5exv20+3Kb13cmGli1hrD6hks= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -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.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/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/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/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 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -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/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= -github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -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/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= -github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -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/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= -github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.9.8/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= -github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -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/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/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -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/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 h1:TmHmbvxPmaegwhDubVz0lICL0J5Ka2vwTzhoePEXsGE= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= +github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= +github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= -github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= -github.com/linkedin/goavro/v2 v2.10.1 h1:ExVurHDnf0eyUocILs48kiZ4pGvaEbDvBOQcfLruA/0= -github.com/linkedin/goavro/v2 v2.10.1/go.mod h1:UgQUb2N/pmueQYH9bfqFioWxzYCZXSfF8Jw03O5sjqA= -github.com/luna-duclos/instrumentedsql v1.1.3 h1:t7mvC0z1jUt5A0UQ6I/0H31ryymuQRnJcWCiqV3lSAA= -github.com/luna-duclos/instrumentedsql v1.1.3/go.mod h1:9J1njvFds+zN7y85EDhN9XNQLANWwZt2ULeIC8yMNYs= -github.com/luna-duclos/instrumentedsql/opentracing v0.0.0-20201103091713-40d03108b6f4 h1:b8Uu5JfweuhcXIqANFs9dOw5zanFj89GYOGlyys37ds= -github.com/luna-duclos/instrumentedsql/opentracing v0.0.0-20201103091713-40d03108b6f4/go.mod h1:YnZVBK+MxEr2sn1rbf4UMqsBd0uKaCOq52UtmbfDKNM= -github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= -github.com/mitchellh/mapstructure v1.4.3/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/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= -github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.16.0 h1:6gjqkI8iiRHMvdccRJM8rVKjCWk6ZIm6FTm3ddIe4/c= -github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/linkedin/goavro/v2 v2.13.0 h1:L8eI8GcuciwUkt41Ej62joSZS4kKaYIUdze+6for9NU= +github.com/linkedin/goavro/v2 v2.13.0/go.mod h1:KXx+erlq+RPlGSPmLF7xGo6SAbh8sCQ53x064+ioxhk= +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/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= +github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= -github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opentracing-contrib/go-stdlib v1.0.0 h1:TBS7YuVotp8myLon4Pv7BtCBzOTo1DeZCld0Z63mW2w= -github.com/opentracing-contrib/go-stdlib v1.0.0/go.mod h1:qtI1ogk+2JhVPIXVc6q+NHziSmy2W5GbdQZFUHADCBU= -github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= -github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= -github.com/pierrec/lz4 v2.6.0+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= -github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= -github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= -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/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= +github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= +github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= +github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -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_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/segmentio/kafka-go v0.4.25 h1:QVx9yz12syKBFkxR+dVDDwTO0ItHgnjjhIdBfqizj+8= -github.com/segmentio/kafka-go v0.4.25/go.mod h1:XzMcoMjSzDGHcIwpWUI7GB43iKZ2fTVmryPSGLf/MPg= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= -github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E= +github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/segmentio/kafka-go v0.4.47 h1:IqziR4pA3vrZq7YdRxaT3w1/5fvIH5qpCwstUanQQB0= +github.com/segmentio/kafka-go v0.4.47/go.mod h1:HjF6XbOKh0Pjlkr5GVZxt6CsjjwnmhVOfURM5KMd8qg= 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/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o= -github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= -github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg= -github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= -github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c h1:u40Z8hqBAAQyv+vATcGgV0YCnDjqSL7/q/JyPhhJSPk= -github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= -github.com/xdg/stringprep v1.0.0 h1:d9X0esnoa3dFsV0FG35rAT0RIhYFlPq7MiP+DW89La0= -github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.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.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/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= -go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.11-0.20210813005559-691160354723 h1:sHOAIxRGBp443oHZIPB+HsUGaksVCXVQENPxwTfQdH4= -go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec= -go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI= -go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= +github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= +github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= +github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.57.0 h1:qtFISDHKolvIxzSs0gIaiPUPR0Cucb0F2coHC7ZLdps= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.57.0/go.mod h1:Y+Pop1Q6hCOnETWTW4NROK/q1hv50hM7yDaUTjG8lp8= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0 h1:DheMAlT6POBP+gh8RUH19EOTnQIor5QE0uSRPtzCpSw= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0/go.mod h1:wZcGmeVO9nzP67aYSLDqXNWK87EZWhi7JWj1v7ZXf94= +go.opentelemetry.io/contrib/instrumentation/runtime v0.57.0 h1:kJB5wMVorwre8QzEodzTAbzm9FOOah0zvG+V4abNlEE= +go.opentelemetry.io/contrib/instrumentation/runtime v0.57.0/go.mod h1:Nup4TgnOyEJWmVq9sf/ASH3ZJiAXwWHd5xZCHG7Sg9M= +go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= +go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.32.0 h1:j7ZSD+5yn+lo3sGV69nW04rRR0jhYnBwjuX3r0HvnK0= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.32.0/go.mod h1:WXbYJTUaZXAbYd8lbgGuvih0yuCfOFC5RJoYnoLcGz8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0 h1:IJFEoHiytixx8cMiVAO+GmHR6Frwu+u5Ur8njpFO6Ac= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0/go.mod h1:3rHrKNtLIoS0oZwkY2vxi+oJcwFRWdtUyRII+so45p8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.32.0 h1:9kV11HXBHZAvuPUZxmMWrH8hZn/6UnHX4K0mu36vNsU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.32.0/go.mod h1:JyA0FHXe22E1NeNiHmVp7kFHglnexDQ7uRWDiiJ1hKQ= +go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= +go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= +go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= +go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= +go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiyYCU9snn1CU= +go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ= +go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= +go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= +go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= +go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190506204251-e1dfcc566284/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -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-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -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-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -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/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.2/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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -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-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 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-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-20200520004742-59133d7f0dd7/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-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-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211209124913-491a49abca63 h1:iocB37TsdFuN6IBRZ+ry36wrkoV51/tl5vOWqkcPGvY= -golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -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-20210514164344-f6687ab2804c/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/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= +golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= 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 h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-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-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/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-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/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-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211210111614-af8b64212486 h1:5hpz5aRr+W1erYCL5JRhSUBJRph7l9XkNveoExlrKYk= -golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= +golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 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/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= 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/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -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/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-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= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -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-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-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-20200619180055-7c47624df98f/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-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= -gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= -gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= -gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= -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/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/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= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -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-20200423170343-7949de9c1215/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-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-20211208223120-3a66f561d7aa h1:I0YcKz0I7OAhddo7ya8kMnvprhcWM045PmkBdMO9zN0= -google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -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.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.42.0 h1:XT2/MFpuPFsEX2fWh3YQtHkZ+WYZFQRfaUgLZYj/p6A= -google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -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= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -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= -google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697 h1:pgr/4QbFyktUv9CtQ/Fq4gzEE6/Xs7iCXbktaGzLHbQ= +google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697/go.mod h1:+D9ySVjN8nY8YCVjc5O7PZDIdZporIDY3KaGfJunh88= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697 h1:LWZqQOEjDyONlF1H6afSWpAL/znlREo2tHfLoe+8LMA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= +google.golang.org/grpc v1.68.0 h1:aHQeeJbo8zAkAa3pRzrVjZlbz6uSfeOXlJNQM0RAbz0= +google.golang.org/grpc v1.68.0/go.mod h1:fmSPC5AsjSBCK54MyHRx48kpOti1/jRfOlwEWywNjWA= +google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= +google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= 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/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v9 v9.31.0 h1:bmXmP2RSNtFES+bn4uYuHT7iJFJv7Vj+an+ZQdDaD1M= gopkg.in/go-playground/validator.v9 v9.31.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -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.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/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/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/golangci.yml b/golangci.yml index 442a6b1..ce8de00 100644 --- a/golangci.yml +++ b/golangci.yml @@ -9,7 +9,8 @@ run: # Output configuration options. output: - format: colored-line-number + formats: + - format: colored-line-number print-issued-lines: true print-linter-name: true @@ -39,7 +40,6 @@ linters-settings: linters: enable: - bodyclose - - deadcode - dupl - errcheck - goconst @@ -54,12 +54,10 @@ linters: - misspell - nakedret - staticcheck - - structcheck - stylecheck - unconvert - unparam - unused - - varcheck enable-all: false fast: false diff --git a/internal/bootstrap/bootstrap.go b/internal/bootstrap/bootstrap.go index efdcd79..761a865 100644 --- a/internal/bootstrap/bootstrap.go +++ b/internal/bootstrap/bootstrap.go @@ -8,6 +8,7 @@ import ( "github.com/bendbennett/go-api-demo/internal/log" "github.com/bendbennett/go-api-demo/internal/storage/elastic" "github.com/bendbennett/go-api-demo/internal/storage/redis" + "github.com/bendbennett/go-api-demo/internal/telemetry" ) // New configures a logger for use throughout the application, @@ -28,9 +29,18 @@ func New() *app.App { panic(err) } + telemetry, err := telemetry.NewTelemetry( + logger, + conf.Telemetry, + ) + if err != nil { + logger.Panic(err) + } + components = append(components, telemetry) + userCache, closer, err := redis.NewUserCache( conf.Redis, - conf.Tracing.Enabled, + conf.Telemetry.Enabled, ) if err != nil { logger.Panic(err) @@ -39,7 +49,7 @@ func New() *app.App { userSearch, err := elastic.NewUserSearch( conf.Elasticsearch, - conf.Tracing.Enabled, + conf.Telemetry.Enabled, ) if err != nil { logger.Panic(err) diff --git a/internal/bootstrap/consumer.go b/internal/bootstrap/consumer.go index 31efdb8..3af4b41 100644 --- a/internal/bootstrap/consumer.go +++ b/internal/bootstrap/consumer.go @@ -10,6 +10,7 @@ import ( "github.com/bendbennett/go-api-demo/internal/config" "github.com/bendbennett/go-api-demo/internal/consume" "github.com/bendbennett/go-api-demo/internal/log" + "github.com/bendbennett/go-api-demo/internal/metrics" "github.com/bendbennett/go-api-demo/internal/user" userconsume "github.com/bendbennett/go-api-demo/internal/user/consume" ) @@ -27,7 +28,7 @@ func newConsumers( err := consume.CreateTopics(conf.TopicConfigs) if err != nil { - panic(err) + return nil, nil, err } schemaClient := schema.NewClient(conf.SchemaRegistry.ClientTimeout) @@ -42,53 +43,69 @@ func newConsumers( return nil, nil, err } - userConsumerProm, err := consume.NewConsumerProm(conf.Metrics.Enabled) + userConsumerMetrics, err := metrics.NewConsumerMetrics(conf.Telemetry.Enabled) if err != nil { panic(err) } - userConsumerPromUserCache := consume.NewConsumerPromCollector( + userConsumerMetricsLabelsCache := metrics.NewConsumerMetricsLabels( "user", "cache", - conf.Metrics.CollectionInterval, - userConsumerProm, + ) + + userConsumerMetricsCollectorCache := metrics.NewConsumerMetricsCollector( + userConsumerMetrics, + userConsumerMetricsLabelsCache, ) userProcessorCache := userconsume.NewProcessor(userCache) - consumers, closrs := userconsume.NewConsumers( + consumers, closrs, err := consume.NewConsumers( conf.UserConsumerCache, - conf.Tracing.Enabled, - userConsumerPromUserCache, + conf.Telemetry.Enabled, + userConsumerMetricsLabelsCache, + userConsumerMetricsCollectorCache, userProcessorCache, userDecoder, logger, ) + if err != nil { + return nil, nil, err + } + for _, consumer := range consumers { components = append(components, consumer) } closers = addCloser(closers, closrs...) - userConsumerPromUserSearch := consume.NewConsumerPromCollector( + userConsumerMetricsLabelsSearch := metrics.NewConsumerMetricsLabels( "user", "search", - conf.Metrics.CollectionInterval, - userConsumerProm, + ) + + userConsumerMetricsCollectorSearch := metrics.NewConsumerMetricsCollector( + userConsumerMetrics, + userConsumerMetricsLabelsSearch, ) userProcessorSearch := userconsume.NewProcessor(userSearch) - consumers, closrs = userconsume.NewConsumers( + consumers, closrs, err = consume.NewConsumers( conf.UserConsumerSearch, - conf.Tracing.Enabled, - userConsumerPromUserSearch, + conf.Telemetry.Enabled, + userConsumerMetricsLabelsSearch, + userConsumerMetricsCollectorSearch, userProcessorSearch, userDecoder, logger, ) + if err != nil { + return nil, nil, err + } + for _, consumer := range consumers { components = append(components, consumer) } diff --git a/internal/bootstrap/router.go b/internal/bootstrap/router.go index ec92c71..c6a590e 100644 --- a/internal/bootstrap/router.go +++ b/internal/bootstrap/router.go @@ -8,7 +8,6 @@ import ( "github.com/bendbennett/go-api-demo/internal/log" "github.com/bendbennett/go-api-demo/internal/routing" "github.com/bendbennett/go-api-demo/internal/sanitise" - "github.com/bendbennett/go-api-demo/internal/trace" "github.com/bendbennett/go-api-demo/internal/user" usercreate "github.com/bendbennett/go-api-demo/internal/user/create" userread "github.com/bendbennett/go-api-demo/internal/user/read" @@ -35,7 +34,7 @@ func newRouters( userStorage, closer, err := newUserStorage( conf.MySQL, conf.Storage, - conf.Tracing.Enabled, + conf.Telemetry.Enabled, ) if err != nil { logger.Panic(err) @@ -77,23 +76,12 @@ func newRouters( UserSearchController: userSearchControllerHTTP.Search, } - httpProm, err := routing.NewHTTPProm(conf.Metrics.Enabled) - if err != nil { - logger.Panic(err) - } - - tracer, closer, err := trace.NewTracer(logger, conf.Tracing.Enabled) - if err != nil { - logger.Panic(err) - } - closers = addCloser(closers, closer) - httpRouter := routing.NewHTTPRouter( httpControllers, logger, - httpProm, - tracer, - conf.HTTPPort, + conf.Telemetry.Enabled, + conf.HTTP.Port, + conf.HTTP.ReadHeaderTimeout, ) components = append(components, httpRouter) @@ -127,8 +115,7 @@ func newRouters( grpcRouter := routing.NewGRPCRouter( grpcControllers, logger, - conf.Metrics.Enabled, - conf.Tracing.Enabled, + conf.Telemetry.Enabled, conf.GRPCPort, ) diff --git a/internal/bootstrap/storage.go b/internal/bootstrap/storage.go index 5f2f2e4..dbd91c4 100644 --- a/internal/bootstrap/storage.go +++ b/internal/bootstrap/storage.go @@ -5,19 +5,19 @@ import ( "fmt" "io" + "github.com/XSAM/otelsql" "github.com/bendbennett/go-api-demo/internal/config" "github.com/bendbennett/go-api-demo/internal/storage/memory" "github.com/bendbennett/go-api-demo/internal/storage/mysql" "github.com/bendbennett/go-api-demo/internal/user" sqldriver "github.com/go-sql-driver/mysql" - sqltracing "github.com/luna-duclos/instrumentedsql" - sqlopentracing "github.com/luna-duclos/instrumentedsql/opentracing" + semconv "go.opentelemetry.io/otel/semconv/v1.26.0" ) func newUserStorage( mySQLConf *sqldriver.Config, storageConf config.Storage, - isTracingEnabled bool, + telemetryEnabled bool, ) (user.CreatorReader, io.Closer, error) { var ( handle interface{} @@ -27,7 +27,7 @@ func newUserStorage( if storageConf.Type == config.StorageTypeSQL { handle, err = sqlDB( mySQLConf, - isTracingEnabled, + telemetryEnabled, ) if err != nil { return nil, nil, err @@ -47,25 +47,20 @@ func newUserStorage( func sqlDB( conf *sqldriver.Config, - tracingEnabled bool, + telemetryEnabled bool, ) (*sql.DB, error) { - driverName := "mysql" + var db *sql.DB + var err error - if tracingEnabled { - driverName = "instrumented-mysql" - sql.Register( - driverName, - sqltracing.WrapDriver( - sqldriver.MySQLDriver{}, - sqltracing.WithTracer(sqlopentracing.NewTracer(true)), - ), - ) + switch telemetryEnabled { + case true: + db, err = otelsql.Open("mysql", conf.FormatDSN(), otelsql.WithAttributes( + semconv.DBSystemMySQL, + )) + default: + db, err = sql.Open("mysql", conf.FormatDSN()) } - db, err := sql.Open( - driverName, - conf.FormatDSN(), - ) if err != nil { return nil, fmt.Errorf( "failed to connect to db: %w", diff --git a/internal/config/config.go b/internal/config/config.go index b9cb4de..8781b01 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -7,13 +7,11 @@ import ( "strings" "time" - "github.com/segmentio/kafka-go" - - "github.com/elastic/go-elasticsearch/v7" - - "github.com/go-redis/redis/v8" + "github.com/elastic/go-elasticsearch/v8" "github.com/go-sql-driver/mysql" "github.com/joho/godotenv" + "github.com/redis/go-redis/v9" + "github.com/segmentio/kafka-go" ) const StorageTypeMemory = "memory" @@ -26,27 +24,29 @@ type Config struct { Elasticsearch elasticsearch.Config TopicConfigs TopicConfigs SchemaRegistry SchemaRegistry + Telemetry Telemetry UserConsumerCache KafkaConsumer UserConsumerSearch KafkaConsumer - Metrics Metrics - Tracing Tracing Logging Logging - HTTPPort int + HTTP HTTP GRPCPort int } +type HTTP struct { + Port int + ReadHeaderTimeout time.Duration +} + type Storage struct { Type string QueryTimeout time.Duration } -type Metrics struct { - Enabled bool - CollectionInterval time.Duration -} - -type Tracing struct { - Enabled bool +type Telemetry struct { + ServiceName string + ExporterTargetEndPoint string + MetricsCollectionInterval time.Duration + Enabled bool } type Logging struct { @@ -95,7 +95,7 @@ func New() Config { GetEnvAsString( "MYSQL_HOST", "localhost"), - GetEnvAsInt(""+ + GetEnvAsInt( "MYSQL_PORT", 3306), ), @@ -105,6 +105,7 @@ func New() Config { ), ParseTime: true, AllowNativePasswords: true, + InterpolateParams: true, }, Storage: Storage{ Type: GetEnvAsString( @@ -116,18 +117,23 @@ func New() Config { 3*time.Second, ), }, - Metrics: Metrics{ - Enabled: GetEnvAsBool( - "METRICS_ENABLED", - true, + Telemetry: Telemetry{ + ServiceName: GetEnvAsString( + "TELEMETRY_SERVICE_NAME", + "go-api-demo", + ), + // OTEL_EXPORTER_OTLP_ENDPOINT is env var for base endpoint URL for any signal type. + // https://opentelemetry.io/docs/languages/sdk-configuration/otlp-exporter/ + ExporterTargetEndPoint: GetEnvAsString( + "TELEMETRY_EXPORTER_TARGET_ENDPOINT", + "0.0.0.0:4317", + ), + MetricsCollectionInterval: GetEnvAsDuration( + "TELEMETRY_METRICS_COLLECTION_INTERVAL", + 5*time.Second, ), - CollectionInterval: GetEnvAsDuration( - "METRICS_COLLECTION_INTERVAL", - 5*time.Second), - }, - Tracing: Tracing{ Enabled: GetEnvAsBool( - "TRACING_ENABLED", + "TELEMETRY_ENABLED", true, ), }, @@ -219,7 +225,7 @@ func New() Config { ), Conf: []kafka.TopicConfig{ { - Topic: "go_api_demo_db.go-api-demo.users", + Topic: "mysql.go_api_demo.users", NumPartitions: 2, ReplicationFactor: 1, ConfigEntries: []kafka.ConfigEntry{ @@ -259,7 +265,7 @@ func New() Config { "/subjects/%v/versions/%v", GetEnvAsString( "KAFKA_SCHEMA_REGISTRY_USERS_VALUE", - "go_api_demo_db.go-api-demo.users-value", + "mysql.go_api_demo.users-value", ), GetEnvAsString( "KAFKA_SCHEMA_REGISTRY_USERS_VALUE_VERSION", @@ -268,10 +274,16 @@ func New() Config { ), }, }, - HTTPPort: GetEnvAsInt( - "HTTP_PORT", - 3000, - ), + HTTP: HTTP{ + Port: GetEnvAsInt( + "HTTP_PORT", + 3000, + ), + ReadHeaderTimeout: GetEnvAsDuration( + "HTTP_READ_HEADER_TIMEOUT", + 10*time.Second, + ), + }, GRPCPort: GetEnvAsInt( "GRPC_PORT", 1234, diff --git a/internal/consume/consumer.go b/internal/consume/consumer.go new file mode 100644 index 0000000..ec1ee46 --- /dev/null +++ b/internal/consume/consumer.go @@ -0,0 +1,165 @@ +package consume + +import ( + "context" + "fmt" + "io" + + "github.com/bendbennett/go-api-demo/internal/config" + "github.com/bendbennett/go-api-demo/internal/log" + "github.com/bendbennett/go-api-demo/internal/metrics" + "github.com/segmentio/kafka-go" + "go.opentelemetry.io/otel" +) + +type reader interface { + FetchMessage(context.Context) (kafka.Message, error) + CommitMessages(context.Context, ...kafka.Message) error + Stats() kafka.ReaderStats +} + +type consumeFunc func(context.Context, *c, kafka.Message) error + +type decoder interface { + Decode([]byte) (interface{}, error) +} + +type processor interface { + Process(context.Context, any) error +} + +type c struct { + reader reader + consumeFunc consumeFunc + processor processor + log log.Logger + decoder decoder + groupID string +} + +func NewConsumers( + conf config.KafkaConsumer, + telemetryEnabled bool, + consumerMetricsLabels metrics.ConsumerMetricsLabels, + consumerMetricsCollector metrics.ConsumerMetricsCollector, + processor processor, + decoder decoder, + log log.Logger, +) ([]*c, []io.Closer, error) { + var ( + consumers []*c + closers []io.Closer + ) + + for i := 0; i < conf.Num; i++ { + reader := kafka.NewReader(conf.ReaderConfig) + + consumeFunc := cf( + telemetryEnabled, + consumerMetricsLabels.EntityType(), + consumerMetricsLabels.Destination(), + ) + + groupID := fmt.Sprintf("%v-%v", conf.ReaderConfig.GroupID, i) + + err := consumerMetricsCollector.RegisterMetrics(telemetryEnabled, reader.Stats, groupID) + + if err != nil { + return nil, nil, err + } + + consumers = append(consumers, &c{ + reader: reader, + consumeFunc: consumeFunc, + processor: processor, + log: log, + groupID: groupID, + decoder: decoder, + }) + + closers = append(closers, reader) + } + + return consumers, closers, nil +} + +// Run is executed in a loop to continuously consume messages. +// TODO: Implement retry topic for error cases. +func (c *c) Run(ctx context.Context) error { + for { + msg, err := c.reader.FetchMessage(ctx) + if err != nil { + if err == ctx.Err() { + c.log.Infof(err.Error()) + return nil + } + + c.log.Error(err) + continue + } + + err = c.consumeFunc(ctx, c, msg) + if err != nil { + c.log.Error(err) + } + } +} + +// consume parses the msg and then calls Process. +// The Kafka connector emits events with a non-nil key and a nil value as these represent "tombstone" +// events for use by compaction. We therefore need to check whether the msg.Value is nil and if so, +// the message should be committed and ignored. +func consume( + ctx context.Context, + c *c, + msg kafka.Message, +) error { + if msg.Value == nil { + err := c.reader.CommitMessages(ctx, msg) + if err != nil { + return err + } + return nil + } + + // https://stackoverflow.com/questions/40548909/consume-kafka-avro-messages-in-go + nMsg, err := c.decoder.Decode(msg.Value) + if err != nil { + return err + } + + err = c.processor.Process(ctx, nMsg) + if err != nil { + return err + } + + err = c.reader.CommitMessages(ctx, msg) + if err != nil { + return err + } + + return nil +} + +// cf decorates consume func with tracing if telemetry is enabled. We avoid wrapping tracing +// around c.reader.FetchMessage as this function blocks, so in cases where we are +// waiting for messages to arrive this produces spans that include the wait time. +func cf( + telemetryEnabled bool, + entityType string, + destination string, +) consumeFunc { + if telemetryEnabled { + return func(ctx context.Context, c *c, msg kafka.Message) error { + ctx, oSpan := otel.GetTracerProvider().Tracer("").Start( + ctx, + fmt.Sprintf("consume: %s: %s", destination, entityType), + ) + defer oSpan.End() + + return consume(ctx, c, msg) + } + } + + return consume +} diff --git a/internal/consume/consumer_test.go b/internal/consume/consumer_test.go new file mode 100644 index 0000000..fda6861 --- /dev/null +++ b/internal/consume/consumer_test.go @@ -0,0 +1,96 @@ +package consume + +import ( + "context" + "testing" + + "github.com/bendbennett/go-api-demo/internal/log" + "github.com/segmentio/kafka-go" + "github.com/stretchr/testify/assert" +) + +type readerMock struct { +} + +func (r *readerMock) FetchMessage(ctx context.Context) (kafka.Message, error) { + select { + case <-ctx.Done(): + return kafka.Message{}, ctx.Err() + default: + } + + return kafka.Message{}, nil +} + +func (r *readerMock) CommitMessages(context.Context, ...kafka.Message) error { + return nil +} + +func (r *readerMock) Stats() kafka.ReaderStats { + return kafka.ReaderStats{} +} + +type processorMock struct { +} + +func (p *processorMock) Process(_ context.Context, data any) error { + return nil +} + +type logMock struct { +} + +func (l *logMock) Panic(error) { + panic("implement me") +} + +func (l *logMock) Panicf(string, ...interface{}) { + panic("implement me") +} + +func (l *logMock) Error(error) { + panic("implement me") +} + +func (l *logMock) Errorf(string, ...interface{}) { + panic("implement me") +} + +func (l *logMock) Infof(string, ...interface{}) { +} + +func (l *logMock) WithSpan(context.Context) log.Logger { + panic("implement me") +} + +// TODO: Consume only returns error when context is cancelled. +// Once the event handling for error conditions is in place, +// should test whether events are being pushed onto retry topic +// or not. For errors generated by unmarshalling, a separate +// topic from the retry topic should be implemented. +func TestUserConsumer_Consume(t *testing.T) { + cases := []struct { + name string + consumer *c + }{ + { + "user consumer consume logs and returns nil", + &c{ + reader: &readerMock{}, + consumeFunc: consume, + processor: &processorMock{}, + log: &logMock{}, + }, + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + cancel() + err := c.consumer.Run(ctx) + + assert.NoError(t, err) + }) + } +} diff --git a/internal/consume/prom.go b/internal/consume/prom.go deleted file mode 100644 index c6e10d1..0000000 --- a/internal/consume/prom.go +++ /dev/null @@ -1,132 +0,0 @@ -package consume - -import ( - "time" - - "github.com/prometheus/client_golang/prometheus" -) - -func NewConsumerProm(metricsEnabled bool) (Prom, error) { - if !metricsEnabled { - return Prom{}, nil - } - - msgCounter := prometheus.NewCounterVec( - prometheus.CounterOpts{ - Name: "consumer_messages_total", - Help: "Total number of Kafka messages consumed regardless of success or failure", - }, - []string{"type", "processor", "consumer"}, - ) - - err := prometheus.Register(msgCounter) - if err != nil { - if _, ok := err.(prometheus.AlreadyRegisteredError); !ok { - return Prom{}, err - } - } - - queueLengthGauge := prometheus.NewGaugeVec( - prometheus.GaugeOpts{ - Name: "consumer_queue_length", - Help: "Queue length of Kafka consumer", - }, - []string{"type", "processor", "consumer"}, - ) - - err = prometheus.Register(queueLengthGauge) - if err != nil { - if _, ok := err.(prometheus.AlreadyRegisteredError); !ok { - return Prom{}, err - } - } - - queueCapacityGauge := prometheus.NewGaugeVec( - prometheus.GaugeOpts{ - Name: "consumer_queue_capacity", - Help: "Queue capacity of Kafka consumer", - }, - []string{"type", "processor", "consumer"}, - ) - - err = prometheus.Register(queueCapacityGauge) - if err != nil { - if _, ok := err.(prometheus.AlreadyRegisteredError); !ok { - return Prom{}, err - } - } - - lagGauge := prometheus.NewGaugeVec( - prometheus.GaugeOpts{ - Name: "consumer_lag", - Help: "Lag of Kafka consumer", - }, - []string{"type", "processor", "consumer"}, - ) - - err = prometheus.Register(lagGauge) - if err != nil { - if _, ok := err.(prometheus.AlreadyRegisteredError); !ok { - return Prom{}, err - } - } - - return Prom{ - MsgCounter: msgCounter, - QueueLengthGauge: queueLengthGauge, - QueueCapacityGauge: queueCapacityGauge, - LagGauge: lagGauge, - }, nil -} - -func NewConsumerPromCollector( - t, p string, - collectInt time.Duration, - prom Prom, -) PromCollector { - return PromCollector{ - Type: t, - Processor: p, - Interval: collectInt, - Prom: prom, - } -} - -type PromCollector struct { - Prom Prom - Type string - Processor string - Interval time.Duration -} - -type Prom struct { - MsgCounter *prometheus.CounterVec - QueueLengthGauge *prometheus.GaugeVec - QueueCapacityGauge *prometheus.GaugeVec - LagGauge *prometheus.GaugeVec -} - -type Stats struct { - Messages int64 - QueueLength int64 - QueueCapacity int64 - Lag int64 -} - -func (c PromCollector) Update(stats Stats, consumer string) { - if c.Prom.MsgCounter != nil { - c.Prom.MsgCounter.WithLabelValues(c.Type, c.Processor, consumer).Add(float64(stats.Messages)) - } - - if c.Prom.QueueLengthGauge != nil { - c.Prom.QueueLengthGauge.WithLabelValues(c.Type, c.Processor, consumer).Set(float64(stats.QueueLength)) - } - - if c.Prom.QueueCapacityGauge != nil { - c.Prom.QueueCapacityGauge.WithLabelValues(c.Type, c.Processor, consumer).Set(float64(stats.QueueCapacity)) - } - - if c.Prom.LagGauge != nil { - c.Prom.LagGauge.WithLabelValues(c.Type, c.Processor, consumer).Set(float64(stats.Lag)) - } -} diff --git a/internal/format/format.go b/internal/format/format.go new file mode 100644 index 0000000..29e9298 --- /dev/null +++ b/internal/format/format.go @@ -0,0 +1,25 @@ +package format + +import "time" + +// MsecToTime converts msec to time.Time. +// As the first arg to time.Unix is expected to be sec, the supplied +// value needs to be divided by 1000. The second arg to time.Unix is +// nsec, so the msec that remain after converting to sec are +// subtracted and multiplied by 1000000. +func MsecToTime(msec int64) time.Time { + const ( + divisor = 1e3 + multiplier = 1e6 + ) + + t := time.Time{} + + if msec > 0 { + sec := msec / divisor + nsec := (msec - (sec * divisor)) * multiplier + t = time.Unix(sec, nsec) + } + + return t +} diff --git a/internal/log/logger.go b/internal/log/logger.go index 635aca8..bc669f0 100644 --- a/internal/log/logger.go +++ b/internal/log/logger.go @@ -5,14 +5,13 @@ import ( "fmt" "github.com/bendbennett/go-api-demo/internal/app" - - "github.com/opentracing/opentracing-go" - "github.com/uber/jaeger-client-go" - "go.uber.org/zap/zapcore" - + "go.opentelemetry.io/otel/trace" "go.uber.org/zap" + "go.uber.org/zap/zapcore" ) +const callerSkip = 1 + type Logger interface { Panic(err error) Panicf(msg string, args ...interface{}) @@ -30,9 +29,17 @@ func NewLogger(prod bool) (logger, error) { switch prod { case true: - zapLogger, err = zap.NewProduction() + zapLogger, err = zap.NewProduction( + zap.AddCallerSkip( + callerSkip, + ), + ) default: - zapLogger, err = zap.NewDevelopment() + zapLogger, err = zap.NewDevelopment( + zap.AddCallerSkip( + callerSkip, + ), + ) } if err != nil { return logger{}, err @@ -69,17 +76,17 @@ func (l logger) Infof(msg string, args ...interface{}) { } func (l logger) WithSpan(ctx context.Context) Logger { - if span := opentracing.SpanFromContext(ctx); span != nil { + // span.IsRecording() determines whether span is noopSpan, + // which is generated when tracing has not been configured. + if span := trace.SpanFromContext(ctx); span.IsRecording() { spanLogger := spanLogger{ logger: l.logger, span: span, } - if jaegerCtx, ok := span.Context().(jaeger.SpanContext); ok { - spanLogger.spanFields = []zapcore.Field{ - zap.String("trace_id", jaegerCtx.TraceID().String()), - zap.String("span_id", jaegerCtx.SpanID().String()), - } + spanLogger.spanFields = []zapcore.Field{ + zap.String("trace_id", span.SpanContext().TraceID().String()), + zap.String("span_id", span.SpanContext().SpanID().String()), } return spanLogger diff --git a/internal/log/spanlogger.go b/internal/log/spanlogger.go index 8087e7b..dd30486 100644 --- a/internal/log/spanlogger.go +++ b/internal/log/spanlogger.go @@ -4,16 +4,15 @@ import ( "context" "fmt" - "github.com/opentracing/opentracing-go" - "github.com/opentracing/opentracing-go/log" - "go.uber.org/zap/zapcore" - + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" "go.uber.org/zap" + "go.uber.org/zap/zapcore" ) type spanLogger struct { logger *zap.Logger - span opentracing.Span + span trace.Span spanFields []zapcore.Field } @@ -56,9 +55,6 @@ func (sl spanLogger) logToSpan(level string, msg string) { return } - fields := make([]log.Field, 0, 2) - fields = append(fields, log.String("event", msg)) - fields = append(fields, log.String("level", level)) - - sl.span.LogFields(fields...) + sl.span.SetAttributes(attribute.String("event", msg)) + sl.span.SetAttributes(attribute.String("level", level)) } diff --git a/internal/metrics/metrics.go b/internal/metrics/metrics.go new file mode 100644 index 0000000..b774f11 --- /dev/null +++ b/internal/metrics/metrics.go @@ -0,0 +1,166 @@ +package metrics + +import ( + "context" + + "github.com/segmentio/kafka-go" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/metric" +) + +type ConsumerMetricsLabels struct { + entityType string + destination string +} + +func NewConsumerMetricsLabels( + entityType string, + destination string, +) ConsumerMetricsLabels { + return ConsumerMetricsLabels{ + entityType: entityType, + destination: destination, + } +} + +func (c ConsumerMetricsLabels) EntityType() string { + return c.entityType +} + +func (c ConsumerMetricsLabels) Destination() string { + return c.destination +} + +type ConsumerMetrics struct { + msgCounter metric.Int64ObservableCounter + queueLengthGauge metric.Int64ObservableGauge + queueCapacityGauge metric.Int64ObservableGauge + lagGauge metric.Int64ObservableGauge + totalMsgCount int64 +} + +func NewConsumerMetrics(telemetryEnabled bool) (ConsumerMetrics, error) { + if !telemetryEnabled { + return ConsumerMetrics{}, nil + } + + meter := otel.Meter("") + + msgCounter, err := meter.Int64ObservableCounter( + "kafka_consumer_messages_total", + metric.WithDescription("Total number of Kafka messages consumed regardless of success or failure"), + ) + + if err != nil { + return ConsumerMetrics{}, err + } + + queueLengthGauge, err := meter.Int64ObservableGauge( + "kafka_consumer_queue_length", + metric.WithDescription("Queue length of Kafka consumer"), + ) + + if err != nil { + return ConsumerMetrics{}, err + } + + queueCapacityGauge, err := meter.Int64ObservableGauge( + "kafka_consumer_queue_capacity", + metric.WithDescription("Queue capacity of Kafka consumer"), + ) + + if err != nil { + return ConsumerMetrics{}, err + } + + lagGauge, err := meter.Int64ObservableGauge( + "kafka_consumer_lag", + metric.WithDescription("Lag of Kafka consumer"), + ) + + if err != nil { + return ConsumerMetrics{}, err + } + + return ConsumerMetrics{ + msgCounter: msgCounter, + queueLengthGauge: queueLengthGauge, + queueCapacityGauge: queueCapacityGauge, + lagGauge: lagGauge, + }, nil +} + +type ConsumerMetricsCollector struct { + metrics ConsumerMetrics + metricsLabels ConsumerMetricsLabels +} + +func NewConsumerMetricsCollector( + metrics ConsumerMetrics, + metricsLabels ConsumerMetricsLabels, +) ConsumerMetricsCollector { + return ConsumerMetricsCollector{ + metrics: metrics, + metricsLabels: metricsLabels, + } +} + +type statsFunc func() kafka.ReaderStats + +func (m ConsumerMetricsCollector) RegisterMetrics(telemetryEnabled bool, statsFunc statsFunc, groupID string) error { + if !telemetryEnabled { + return nil + } + + meter := otel.Meter("") + + metricMeasurementOptions := metric.WithAttributes( + attribute.String("consumer", groupID), + attribute.String("entity_type", m.metricsLabels.EntityType()), + attribute.String("destination", m.metricsLabels.Destination()), + ) + + _, err := meter.RegisterCallback( + func(ctx context.Context, o metric.Observer) error { + stats := statsFunc() + + // Maintain a total message count as statsFunc().Messages + // returns count of messages since last snapshot. + // A snapshot is generated each time Stats() is called. + m.metrics.totalMsgCount += stats.Messages + + o.ObserveInt64( + m.metrics.msgCounter, + m.metrics.totalMsgCount, + metricMeasurementOptions, + ) + + o.ObserveInt64( + m.metrics.queueLengthGauge, + stats.QueueLength, + metricMeasurementOptions, + ) + + o.ObserveInt64( + m.metrics.queueCapacityGauge, + stats.QueueCapacity, + metricMeasurementOptions, + ) + + o.ObserveInt64( + m.metrics.lagGauge, + stats.Lag, + metricMeasurementOptions, + ) + + return nil + }, + m.metrics.msgCounter, + m.metrics.queueLengthGauge, + m.metrics.queueCapacityGauge, + m.metrics.lagGauge, + ) + + return err +} diff --git a/internal/routing/grpc.go b/internal/routing/grpc.go index a208120..1bb023a 100644 --- a/internal/routing/grpc.go +++ b/internal/routing/grpc.go @@ -7,20 +7,16 @@ import ( user "github.com/bendbennett/go-api-demo/generated" "github.com/bendbennett/go-api-demo/internal/log" - middleware "github.com/grpc-ecosystem/go-grpc-middleware" - opentracing "github.com/grpc-ecosystem/go-grpc-middleware/tracing/opentracing" - promgrpc "github.com/grpc-ecosystem/go-grpc-prometheus" - "github.com/prometheus/client_golang/prometheus" + "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" "google.golang.org/grpc" "google.golang.org/grpc/reflection" ) type GRPCRouter struct { - userServer *userServer - logger log.Logger - metricsEnabled bool - tracingEnabled bool - port int + userServer *userServer + logger log.Logger + telemetryEnabled bool + port int } type GRPCControllers struct { @@ -34,8 +30,7 @@ type GRPCControllers struct { func NewGRPCRouter( controllers GRPCControllers, logger log.Logger, - metricEnabled bool, - tracingEnabled bool, + telemetryEnabled bool, port int, ) *GRPCRouter { return &GRPCRouter{ @@ -46,8 +41,7 @@ func NewGRPCRouter( UserSearch: controllers.UserSearch, }, logger, - metricEnabled, - tracingEnabled, + telemetryEnabled, port, } } @@ -101,38 +95,10 @@ func (r *GRPCRouter) Run(ctx context.Context) error { r.logger.Panicf("failed to listen: %v", err) } - var ( - streamServerInterceptors []grpc.StreamServerInterceptor - unaryServerInterceptors []grpc.UnaryServerInterceptor - ) - - if r.metricsEnabled { - streamServerInterceptors = append( - streamServerInterceptors, - promgrpc.StreamServerInterceptor, - ) - - unaryServerInterceptors = append( - unaryServerInterceptors, - promgrpc.UnaryServerInterceptor, - ) - } - - if r.tracingEnabled { - streamServerInterceptors = append( - streamServerInterceptors, - opentracing.StreamServerInterceptor(), - ) + serverOptions := []grpc.ServerOption{} - unaryServerInterceptors = append( - unaryServerInterceptors, - opentracing.UnaryServerInterceptor(), - ) - } - - serverOptions := []grpc.ServerOption{ - grpc.StreamInterceptor(middleware.ChainStreamServer(streamServerInterceptors...)), - grpc.UnaryInterceptor(middleware.ChainUnaryServer(unaryServerInterceptors...)), + if r.telemetryEnabled { + serverOptions = append(serverOptions, grpc.StatsHandler(otelgrpc.NewServerHandler())) } s := grpc.NewServer(serverOptions...) @@ -141,17 +107,7 @@ func (r *GRPCRouter) Run(ctx context.Context) error { r.userServer, ) - if r.metricsEnabled { - promgrpc.EnableHandlingTimeHistogram( - func(opts *prometheus.HistogramOpts) { - opts.Name = "grpc_request_duration_seconds" - opts.Help = "A histogram of latencies for gRPC requests." - opts.Buckets = []float64{.001, .002, .005, .01, .02, .05, .1, .2, .5, 1, 2, 5} - }, - ) - promgrpc.Register(s) - } - + // TODO: This should be configurable as it publicly exposes the gRPC endpoints. reflection.Register(s) go func() { diff --git a/internal/routing/http.go b/internal/routing/http.go index 93854a8..02ea473 100644 --- a/internal/routing/http.go +++ b/internal/routing/http.go @@ -6,19 +6,19 @@ import ( "net" "net/http" "net/http/pprof" + "time" "github.com/bendbennett/go-api-demo/internal/log" "github.com/gorilla/mux" - "github.com/opentracing-contrib/go-stdlib/nethttp" - "github.com/opentracing/opentracing-go" - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promhttp" + "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" + "go.opentelemetry.io/otel/attribute" ) type HTTPRouter struct { - handler http.Handler - logger log.Logger - port int + handler http.Handler + logger log.Logger + port int + readHeaderTimeout time.Duration } type HTTPControllers struct { @@ -27,15 +27,10 @@ type HTTPControllers struct { UserSearchController func(w http.ResponseWriter, r *http.Request) } -type HTTPProm struct { - RequestDurationHistogram *prometheus.HistogramVec - RequestCounter *prometheus.CounterVec -} - type route struct { - path string - handler http.HandlerFunc - method string + path string + handlerFunc http.HandlerFunc + method string } // NewHTTPRouter returns a pointer to an HTTPRouter struct populated @@ -43,9 +38,9 @@ type route struct { func NewHTTPRouter( controllers HTTPControllers, logger log.Logger, - httpProm HTTPProm, - tracer opentracing.Tracer, + telemetryEnabled bool, port int, + readHeaderTimeout time.Duration, ) *HTTPRouter { router := mux.NewRouter() @@ -56,11 +51,6 @@ func NewHTTPRouter( }, ) - router.HandleFunc( - "/metrics", - promhttp.Handler().ServeHTTP, - ) - router.HandleFunc( "/debug/pprof/profile", pprof.Profile, @@ -68,81 +58,62 @@ func NewHTTPRouter( routes := []route{ { - path: "/user", - handler: controllers.UserCreateController, - method: http.MethodPost, + path: "/user", + handlerFunc: controllers.UserCreateController, + method: http.MethodPost, }, { - path: "/user", - handler: controllers.UserReadController, - method: http.MethodGet, + path: "/user", + handlerFunc: controllers.UserReadController, + method: http.MethodGet, }, { - path: "/user/search/{searchTerm}", - handler: controllers.UserSearchController, - method: http.MethodGet, + path: "/user/search/{searchTerm}", + handlerFunc: controllers.UserSearchController, + method: http.MethodGet, }, } + telemetryHandlerFunc := func(f http.HandlerFunc, path string) http.HandlerFunc { + if !telemetryEnabled { + return f + } + + return func(w http.ResponseWriter, r *http.Request) { + labeler, _ := otelhttp.LabelerFromContext(r.Context()) + labeler.Add(attribute.String("http_route", path)) + + f(w, r) + } + } + for _, route := range routes { router.HandleFunc( route.path, - wrapMetrics( - httpProm, - route, - ), + telemetryHandlerFunc(route.handlerFunc, route.path), ).Methods(route.method) } - handler := nethttp.Middleware( - tracer, - router, - nethttp.OperationNameFunc(func(r *http.Request) string { - return "HTTP " + r.Method + ": " + r.URL.Path - }), - nethttp.MWSpanFilter(func(r *http.Request) bool { - return r.URL.Path != "/metrics" - }), - ) + var handler http.Handler = router + + if telemetryEnabled { + handler = otelhttp.NewHandler( + router, + "http", + otelhttp.WithSpanNameFormatter(func(operation string, r *http.Request) string { + return operation + ": " + r.Method + ": " + r.URL.Path + }), + ) + } return &HTTPRouter{ handler, logger, port, + readHeaderTimeout, } } -func wrapMetrics( - httpProm HTTPProm, - route route, -) http.HandlerFunc { - if httpProm.RequestCounter != nil { - route.handler = promhttp.InstrumentHandlerCounter( - httpProm.RequestCounter.MustCurryWith( - prometheus.Labels{ - "route": route.path, - "method": route.method, - }, - ), - route.handler, - ) - } - - if httpProm.RequestDurationHistogram != nil { - route.handler = promhttp.InstrumentHandlerDuration( - httpProm.RequestDurationHistogram.MustCurryWith( - prometheus.Labels{ - "route": route.path, - "method": route.method, - }, - ), - route.handler, - ) - } - - return route.handler -} - // Run configures and starts an HTTP server. A go routine is // used to listen for context cancellation and triggers // server shutdown. @@ -159,7 +130,8 @@ func (r *HTTPRouter) Run(ctx context.Context) error { } s := http.Server{ - Handler: r.handler, + Handler: r.handler, + ReadHeaderTimeout: r.readHeaderTimeout, } go func() { @@ -182,45 +154,3 @@ func (r *HTTPRouter) Run(ctx context.Context) error { return err } - -func NewHTTPProm(metricsEnabled bool) (HTTPProm, error) { - if !metricsEnabled { - return HTTPProm{}, nil - } - - requestDurationHistogram := prometheus.NewHistogramVec( - prometheus.HistogramOpts{ - Name: "http_request_duration_seconds", - Help: "A histogram of latencies for HTTP requests.", - Buckets: []float64{.001, .002, .005, .01, .02, .05, .1, .2, .5, 1, 2, 5}, - }, - []string{"route", "method", "code"}, - ) - - err := prometheus.Register(requestDurationHistogram) - if err != nil { - if _, ok := err.(prometheus.AlreadyRegisteredError); !ok { - return HTTPProm{}, err - } - } - - requestCounter := prometheus.NewCounterVec( - prometheus.CounterOpts{ - Name: "http_server_handled_total", - Help: "Total number of HTTP requests completed on the server, regardless of success or failure", - }, - []string{"route", "method", "code"}, - ) - - err = prometheus.Register(requestCounter) - if err != nil { - if _, ok := err.(prometheus.AlreadyRegisteredError); !ok { - return HTTPProm{}, err - } - } - - return HTTPProm{ - RequestDurationHistogram: requestDurationHistogram, - RequestCounter: requestCounter, - }, nil -} diff --git a/internal/storage/elastic/user.go b/internal/storage/elastic/user.go index 5983b79..bdd0681 100644 --- a/internal/storage/elastic/user.go +++ b/internal/storage/elastic/user.go @@ -10,13 +10,12 @@ import ( "time" "github.com/pkg/errors" - - "github.com/opentracing/opentracing-go" - "github.com/opentracing/opentracing-go/ext" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" "github.com/bendbennett/go-api-demo/internal/user" - "github.com/elastic/go-elasticsearch/v7" - "github.com/elastic/go-elasticsearch/v7/esapi" + "github.com/elastic/go-elasticsearch/v8" + "github.com/elastic/go-elasticsearch/v8/esapi" ) const usrs = "users" @@ -37,7 +36,7 @@ type r struct { func NewUserSearch( esConf elasticsearch.Config, - isTracingEnabled bool, + telemetryEnabled bool, ) (*userSearch, error) { es, err := elasticsearch.NewClient(esConf) if err != nil { @@ -51,7 +50,7 @@ func NewUserSearch( us := userSearch{es} - if isTracingEnabled { + if telemetryEnabled { us = userSearch{&instrumentSearch{es}} } @@ -239,7 +238,7 @@ type instrumentSearch struct { } func (s *instrumentSearch) Perform(request *http.Request) (*http.Response, error) { - span, _ := opentracing.StartSpanFromContext( + ctx, oSpan := otel.GetTracerProvider().Tracer("").Start( request.Context(), fmt.Sprintf( "HTTP %s: %s", @@ -247,11 +246,15 @@ func (s *instrumentSearch) Perform(request *http.Request) (*http.Response, error request.URL.Path, ), ) - defer span.Finish() + defer oSpan.End() + + oSpan.SetAttributes( + attribute.String("component", "database/elasticsearch"), + attribute.String("http.method", request.Method), + attribute.String("http.url", request.URL.Path), + ) - ext.Component.Set(span, "database/elasticsearch") - ext.HTTPMethod.Set(span, request.Method) - ext.HTTPUrl.Set(span, request.URL.Path) + request = request.Clone(ctx) return s.search.Perform(request) } diff --git a/internal/storage/redis/user.go b/internal/storage/redis/user.go index f93045d..4b856a8 100644 --- a/internal/storage/redis/user.go +++ b/internal/storage/redis/user.go @@ -5,15 +5,14 @@ import ( "encoding/json" "fmt" "io" + "net" "strings" "github.com/pkg/errors" - - "github.com/opentracing/opentracing-go" - "github.com/opentracing/opentracing-go/ext" + "go.opentelemetry.io/otel" "github.com/bendbennett/go-api-demo/internal/user" - "github.com/go-redis/redis/v8" + "github.com/redis/go-redis/v9" ) const usr = "user" @@ -30,7 +29,7 @@ type userCache struct { func NewUserCache( redisConf redis.Options, - isTracingEnabled bool, + telemetryEnabled bool, ) (*userCache, io.Closer, error) { rdb := redis.NewClient( &redis.Options{ @@ -44,7 +43,7 @@ func NewUserCache( return nil, nil, err } - if isTracingEnabled { + if telemetryEnabled { rdb.AddHook(instrumentCache{}) } @@ -125,40 +124,38 @@ func (c *userCache) Read(ctx context.Context) ([]user.User, error) { type instrumentCache struct{} -func (ic instrumentCache) BeforeProcess(ctx context.Context, cmd redis.Cmder) (context.Context, error) { - span, sCtx := opentracing.StartSpanFromContext(ctx, "redis:cmd") - ext.DBType.Set(span, "redis") - ext.DBStatement.Set(span, strings.ToUpper(cmd.Name())) +func (ic instrumentCache) DialHook(next redis.DialHook) redis.DialHook { + return func(ctx context.Context, network, addr string) (net.Conn, error) { + conn, err := next(ctx, network, addr) - return sCtx, nil + return conn, err + } } -func (ic instrumentCache) AfterProcess(ctx context.Context, cmd redis.Cmder) error { - span := opentracing.SpanFromContext(ctx) - if span != nil { - span.Finish() - } +func (ic instrumentCache) ProcessHook(next redis.ProcessHook) redis.ProcessHook { + return func(ctx context.Context, cmd redis.Cmder) error { + ctx, span := otel.GetTracerProvider().Tracer("").Start(ctx, "redis: "+strings.ToUpper(cmd.Name())) + defer span.End() - return nil -} + err := next(ctx, cmd) -func (ic instrumentCache) BeforeProcessPipeline(ctx context.Context, cmds []redis.Cmder) (context.Context, error) { - span, sCtx := opentracing.StartSpanFromContext(ctx, "redis:pipeline-cmd") - ext.DBType.Set(span, "redis") - cmdNames := make([]string, len(cmds)) - for i, cmd := range cmds { - cmdNames[i] = strings.ToUpper(cmd.Name()) + return err } - ext.DBStatement.Set(span, strings.Join(cmdNames, " --> ")) - - return sCtx, nil } -func (ic instrumentCache) AfterProcessPipeline(ctx context.Context, cmds []redis.Cmder) error { - span := opentracing.SpanFromContext(ctx) - if span != nil { - span.Finish() - } +func (ic instrumentCache) ProcessPipelineHook(next redis.ProcessPipelineHook) redis.ProcessPipelineHook { + return func(ctx context.Context, cmds []redis.Cmder) error { + cmdNames := make([]string, len(cmds)) - return nil + for i, cmd := range cmds { + cmdNames[i] = strings.ToUpper(cmd.Name()) + } + + ctx, span := otel.GetTracerProvider().Tracer("").Start(ctx, "redis-pipeline: "+strings.Join(cmdNames, " --> ")) + defer span.End() + + err := next(ctx, cmds) + + return err + } } diff --git a/internal/telemetry/telemetry.go b/internal/telemetry/telemetry.go new file mode 100644 index 0000000..9b9557b --- /dev/null +++ b/internal/telemetry/telemetry.go @@ -0,0 +1,161 @@ +package telemetry + +import ( + "errors" + "time" + + "github.com/bendbennett/go-api-demo/internal/config" + "github.com/bendbennett/go-api-demo/internal/log" + "go.opentelemetry.io/contrib/instrumentation/runtime" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc" + "go.opentelemetry.io/otel/exporters/otlp/otlptrace" + "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" + "go.opentelemetry.io/otel/propagation" + sdkmetric "go.opentelemetry.io/otel/sdk/metric" + "go.opentelemetry.io/otel/sdk/resource" + sdktrace "go.opentelemetry.io/otel/sdk/trace" + semconv "go.opentelemetry.io/otel/semconv/v1.4.0" + "golang.org/x/net/context" +) + +type telemetry struct { + logger log.Logger + conf config.Telemetry +} + +func NewTelemetry( + logger log.Logger, + conf config.Telemetry, +) (*telemetry, error) { + return &telemetry{ + logger: logger, + conf: conf, + }, nil +} + +func (t *telemetry) Run(ctx context.Context) error { + var meterProvider *sdkmetric.MeterProvider + var tracerProvider *sdktrace.TracerProvider + + if t.conf.Enabled { + resource, err := resource.New(ctx, + resource.WithFromEnv(), + resource.WithProcess(), + resource.WithTelemetrySDK(), + resource.WithHost(), + resource.WithAttributes( + // Service name used in traces and metrics (exported_job). + semconv.ServiceNameKey.String(t.conf.ServiceName), + ), + ) + if err != nil { + return err + } + + if meterProvider, err = t.meterProvider(ctx, resource); err != nil { + return err + } + + if tracerProvider, err = t.tracerProvider(ctx, resource); err != nil { + return err + } + } + + <-ctx.Done() + + var providerShutdownErr error + + if tracerProvider != nil { + err := tracerProvider.Shutdown(ctx) + + if !errors.Is(err, context.Canceled) { + t.logger.Error(err) + providerShutdownErr = errors.Join(err) + } + + t.logger.Infof(err.Error()) + } + + if meterProvider != nil { + err := meterProvider.Shutdown(ctx) + + if !errors.Is(err, context.Canceled) { + t.logger.Error(err) + providerShutdownErr = errors.Join(providerShutdownErr, err) + } + + t.logger.Infof(err.Error()) + } + + return providerShutdownErr +} + +func (t *telemetry) meterProvider( + ctx context.Context, + resource *resource.Resource, +) (*sdkmetric.MeterProvider, error) { + metricExporter, err := otlpmetricgrpc.New( + ctx, + otlpmetricgrpc.WithInsecure(), + otlpmetricgrpc.WithEndpoint(t.conf.ExporterTargetEndPoint), + ) + + if err != nil { + return nil, err + } + + meterProvider := sdkmetric.NewMeterProvider( + sdkmetric.WithResource(resource), + sdkmetric.WithReader( + sdkmetric.NewPeriodicReader( + metricExporter, + sdkmetric.WithInterval(2*time.Second), + ), + ), + ) + + // Registers meterProvider as the global meter provider. + otel.SetMeterProvider(meterProvider) + + // Add Go runtime metrics. + err = runtime.Start(runtime.WithMinimumReadMemStatsInterval(time.Second)) + + return meterProvider, err +} + +func (t *telemetry) tracerProvider( + ctx context.Context, + resource *resource.Resource, +) (*sdktrace.TracerProvider, error) { + traceClient := otlptracegrpc.NewClient( + otlptracegrpc.WithInsecure(), + otlptracegrpc.WithEndpoint(t.conf.ExporterTargetEndPoint)) + + traceExporter, err := otlptrace.New(ctx, traceClient) + + if err != nil { + return nil, err + } + + bsp := sdktrace.NewBatchSpanProcessor(traceExporter) + + tracerProvider := sdktrace.NewTracerProvider( + sdktrace.WithSampler(sdktrace.AlwaysSample()), + sdktrace.WithResource(resource), + sdktrace.WithSpanProcessor(bsp), + ) + + // Set global propagator to TraceContext (the default is no-op). + otel.SetTextMapPropagator( + propagation.NewCompositeTextMapPropagator( + propagation.TraceContext{}, + propagation.Baggage{}, + ), + ) + + // Registers tracerProvider as the global trace provider. + otel.SetTracerProvider(tracerProvider) + + return tracerProvider, nil +} diff --git a/internal/trace/tracer.go b/internal/trace/tracer.go deleted file mode 100644 index e5ecc36..0000000 --- a/internal/trace/tracer.go +++ /dev/null @@ -1,54 +0,0 @@ -package trace - -import ( - "io" - - "github.com/bendbennett/go-api-demo/internal/log" - "github.com/opentracing/opentracing-go" - jaegercfg "github.com/uber/jaeger-client-go/config" - jaegerprom "github.com/uber/jaeger-lib/metrics/prometheus" -) - -// NewTracer toggles tracing on the basis of TRACING_ENABLED env var. -// If TRACING_ENABLED is true, the configuration and behaviour of the -// tracer is modified through JAEGER_... env vars. -func NewTracer( - logger log.Logger, - tracingEnabled bool, -) (opentracing.Tracer, io.Closer, error) { - if !tracingEnabled { - return opentracing.NoopTracer{}, nil, nil - } - - cfg, err := jaegercfg.FromEnv() - if err != nil { - logger.Panic(err) - } - - jaegerLogger := jaegerLoggerAdapter{logger} - jaegerMetrics := jaegerprom.New() - - tracer, closer, err := cfg.NewTracer( - jaegercfg.Logger(jaegerLogger), - jaegercfg.Metrics(jaegerMetrics), - ) - if err != nil { - return nil, nil, err - } - - opentracing.SetGlobalTracer(tracer) - - return tracer, closer, nil -} - -type jaegerLoggerAdapter struct { - logger log.Logger -} - -func (l jaegerLoggerAdapter) Error(msg string) { - l.logger.Errorf(msg) -} - -func (l jaegerLoggerAdapter) Infof(msg string, args ...interface{}) { - l.logger.Infof(msg, args...) -} diff --git a/internal/user/consume/consumer.go b/internal/user/consume/consumer.go deleted file mode 100644 index fd29187..0000000 --- a/internal/user/consume/consumer.go +++ /dev/null @@ -1,207 +0,0 @@ -package consume - -import ( - "context" - "fmt" - "io" - "time" - - "github.com/bendbennett/go-api-demo/internal/config" - prom "github.com/bendbennett/go-api-demo/internal/consume" - "github.com/bendbennett/go-api-demo/internal/log" - "github.com/mitchellh/mapstructure" - "github.com/opentracing/opentracing-go" - "github.com/segmentio/kafka-go" -) - -type consumeFunc func(context.Context, *c, kafka.Message) error - -type reader interface { - FetchMessage(context.Context) (kafka.Message, error) - CommitMessages(context.Context, ...kafka.Message) error - Stats() kafka.ReaderStats -} - -type decoder interface { - Decode([]byte) (interface{}, error) -} - -type c struct { - reader reader - consumeFunc consumeFunc - processor Processor - log log.Logger - promID string - decoder decoder - promCollector prom.PromCollector -} - -func NewConsumers( - conf config.KafkaConsumer, - isTracingEnabled bool, - promCollector prom.PromCollector, - processor Processor, - decoder decoder, - log log.Logger, -) ([]*c, []io.Closer) { - var ( - consumers []*c - closers []io.Closer - ) - - for i := 0; i < conf.Num; i++ { - r := kafka.NewReader(conf.ReaderConfig) - - cf := consume - - if isTracingEnabled { - cf = wrappedConsume - } - - consumers = append(consumers, &c{ - reader: r, - consumeFunc: cf, - processor: processor, - promCollector: promCollector, - log: log, - promID: fmt.Sprintf("%v-%v", conf.ReaderConfig.GroupID, i), - decoder: decoder, - }) - - closers = append(closers, r) - } - - return consumers, closers -} - -// Run is executed in a loop to continuously consume messages. -// A goroutine is used to intermittently collect prometheus metrics -// for the Kafka reader. -// TODO: Implement retry topic for error cases. -func (c *c) Run(ctx context.Context) error { - go func() { - ticker := time.NewTicker(c.promCollector.Interval) - - for { - select { - case <-ctx.Done(): - return - case <-ticker.C: - kafkaStats := c.reader.Stats() - - stats := prom.Stats{ - Messages: kafkaStats.Messages, - QueueLength: kafkaStats.QueueLength, - QueueCapacity: kafkaStats.QueueCapacity, - Lag: kafkaStats.Lag, - } - - c.promCollector.Update(stats, c.promID) - } - } - }() - - for { - msg, err := c.reader.FetchMessage(ctx) - if err != nil { - if err == ctx.Err() { - c.log.Infof("%s", err) - return nil - } - - c.log.Error(err) - continue - } - - err = c.consumeFunc(ctx, c, msg) - if err != nil { - c.log.Error(err) - } - } -} - -// consume parses the msg and then calls Process. -// The Kafka connector emits events with a non-nil key and a nil value as these represent "tombstone" -// events for use by compaction. We therefore need to check whether the msg.Value is nil and if so, -// the message should be committed and ignored. -func consume( - ctx context.Context, - c *c, - msg kafka.Message, -) error { - if msg.Value == nil { - err := c.reader.CommitMessages(ctx, msg) - if err != nil { - return err - } - return nil - } - - // https://stackoverflow.com/questions/40548909/consume-kafka-avro-messages-in-go - nMsg, err := c.decoder.Decode(msg.Value) - if err != nil { - return err - } - - m := m{} - - err = mapstructure.Decode(nMsg, &m) - if err != nil { - return err - } - - input := inputData{ - Before: m.Before.Value, - After: m.After.Value, - } - - err = c.processor.Process(ctx, input) - if err != nil { - return err - } - - err = c.reader.CommitMessages(ctx, msg) - if err != nil { - return err - } - - return nil -} - -// wrappedConsume decorates consume func with tracing. We avoid wrapping tracing around -// c.reader.FetchMessage as this function blocks, so in cases where we are waiting for -// messages to arrive this produces spans that include the wait time. -func wrappedConsume( - ctx context.Context, - c *c, - msg kafka.Message, -) error { - span, ctx := opentracing.StartSpanFromContext( - ctx, - "Consume: User", - ) - defer span.Finish() - - return consume(ctx, c, msg) -} - -type m struct { - Before val - After val -} - -type val struct { - Value usr `mapstructure:"go_api_demo_db.go_api_demo.users.Value"` -} - -type usr struct { - ID string `mapstructure:"id"` - FirstName string `mapstructure:"first_name"` - LastName string `mapstructure:"last_name"` - CreatedAt int64 `mapstructure:"created_at"` -} - -type inputData struct { - Before usr - After usr -} diff --git a/internal/user/consume/consumer_test.go b/internal/user/consume/consumer_test.go deleted file mode 100644 index 1d74bd7..0000000 --- a/internal/user/consume/consumer_test.go +++ /dev/null @@ -1,227 +0,0 @@ -package consume - -import ( - "context" - "errors" - "fmt" - "testing" - "time" - - "github.com/mitchellh/mapstructure" - - prom "github.com/bendbennett/go-api-demo/internal/consume" - - "github.com/bendbennett/go-api-demo/internal/log" - - "github.com/segmentio/kafka-go" - "github.com/stretchr/testify/assert" -) - -type readerMock struct { -} - -func (r *readerMock) FetchMessage(ctx context.Context) (kafka.Message, error) { - select { - case <-ctx.Done(): - return kafka.Message{}, ctx.Err() - default: - } - - return kafka.Message{}, nil -} - -func (r *readerMock) CommitMessages(context.Context, ...kafka.Message) error { - return nil -} - -func (r *readerMock) Stats() kafka.ReaderStats { - return kafka.ReaderStats{} -} - -type processorMock struct { -} - -func (p *processorMock) Process(_ context.Context, id inputData) error { - return nil -} - -type logMock struct { -} - -func (l *logMock) Panic(error) { - panic("implement me") -} - -func (l *logMock) Panicf(string, ...interface{}) { - panic("implement me") -} - -func (l *logMock) Error(error) { - panic("implement me") -} - -func (l *logMock) Errorf(string, ...interface{}) { - panic("implement me") -} - -func (l *logMock) Infof(string, ...interface{}) { -} - -func (l *logMock) WithSpan(context.Context) log.Logger { - panic("implement me") -} - -// TODO: Consume only returns error when context is cancelled. -// Once the event handling for error conditions is in place, -// should test whether events are being pushed onto retry topic -// or not. For errors generated by unmarshalling, a separate -// topic from the retry topic should be implemented. -func TestUserConsumer_Consume(t *testing.T) { - cases := []struct { - name string - consumer *c - }{ - { - "user consumer consume logs and returns nil", - &c{ - reader: &readerMock{}, - consumeFunc: consume, - processor: &processorMock{}, - log: &logMock{}, - promCollector: prom.PromCollector{ - Interval: time.Second, - }, - }, - }, - } - - for _, c := range cases { - t.Run(c.name, func(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - cancel() - err := c.consumer.Run(ctx) - - assert.NoError(t, err) - }) - } -} - -var msg = map[string]interface{}{ - "after": map[string]interface{}{ - "go_api_demo_db.go_api_demo.users.Value": map[string]interface{}{ - "created_at": 1639512014000, - "first_name": "john", - "id": "673b3c8c-3589-4b77-af89-94dcda52a861", - "last_name": "smith", - }, - }, - "before": nil, - "op": "c", - "source": map[string]interface{}{ - "connector": "mysql", - "db": "go-api-demo", - "file": "binlog.000002", - "gtid": nil, - "name": "go_api_demo_db", - "pos": 9548, - "query": nil, - "row": 0, - "sequence": nil, - "server_id": 1, - "snapshot": map[string]interface{}{ - "string": "false", - }, - "table": map[string]interface{}{ - "string": "users", - }, - "thread": nil, - "ts_ms": 1639512013000, - "version": "1.7.1.Final", - }, - "transaction": nil, - "ts_ms": map[string]interface{}{ - "long": 1639512013850, - }, -} - -// nolint:gocyclo -func Benchmark_Extract(b *testing.B) { - extractUser := func(msg interface{}, key string) (usr, error) { - valKey := "go_api_demo_db.go_api_demo.users.Value" - - if _, ok := msg.(map[string]interface{}); !ok { - return usr{}, errors.New("cannot assert msg as map[string]interface{}") - } - - m := msg.(map[string]interface{}) - - if _, ok := m[key]; !ok { - return usr{}, fmt.Errorf("%v key missing from msg", key) - } - - if m[key] == nil { - return usr{}, nil - } - - if _, ok := m[key].(map[string]interface{}); !ok { - return usr{}, fmt.Errorf("cannot assert msg[%v] as map[string]interface{}", key) - } - - m = m[key].(map[string]interface{}) - - if _, ok := m[valKey]; !ok { - return usr{}, fmt.Errorf("%v key missing from msg", valKey) - } - - if _, ok := m[valKey].(map[string]interface{}); !ok { - return usr{}, fmt.Errorf("cannot assert msg[%v][%v] as map[string]interface{}", key, valKey) - } - - m = m[valKey].(map[string]interface{}) - - reqKeys := []string{"id", "first_name", "last_name", "created_at"} - - for _, reqKey := range reqKeys { - if _, ok := m[reqKey]; !ok { - return usr{}, fmt.Errorf("%v key missing from msg", reqKey) - } - } - - if _, ok := m["id"].(string); !ok { - return usr{}, errors.New("cannot assert id is string") - } - - if _, ok := m["first_name"].(string); !ok { - return usr{}, errors.New("cannot assert first_name is string") - } - - if _, ok := m["last_name"].(string); !ok { - return usr{}, errors.New("cannot assert last_name is string") - } - - if _, ok := m["created_at"].(int64); !ok { - return usr{}, errors.New("cannot assert created_at is int64") - } - - return usr{ - ID: m["id"].(string), - FirstName: m["first_name"].(string), - LastName: m["last_name"].(string), - CreatedAt: m["created_at"].(int64), - }, nil - } - - for n := 0; n < b.N; n++ { - _, _ = extractUser(msg, "after") - - } -} - -func Benchmark_MapExtract(b *testing.B) { - m := m{} - - for n := 0; n < b.N; n++ { - _ = mapstructure.Decode(msg, &m) - - } -} diff --git a/internal/user/consume/processor.go b/internal/user/consume/processor.go index e16eff2..2aa67a6 100644 --- a/internal/user/consume/processor.go +++ b/internal/user/consume/processor.go @@ -3,23 +3,20 @@ package consume import ( "context" "errors" - "time" + "github.com/bendbennett/go-api-demo/internal/format" "github.com/bendbennett/go-api-demo/internal/user" + "github.com/mitchellh/mapstructure" ) -type p struct { +type processor struct { creator user.Creator } -type Processor interface { - Process(context.Context, inputData) error -} - func NewProcessor( creator user.Creator, -) *p { - return &p{ +) *processor { + return &processor{ creator, } } @@ -30,63 +27,68 @@ func NewProcessor( // filtered out in the consumer, but we are just being defensive. // The second case checks whether before is empty, in which case a user is being created. // TODO: Implement update and delete. -func (p *p) Process( +func (p *processor) Process( ctx context.Context, - inputData inputData, + data any, ) error { - diff := p.userBeforeAfter(inputData) + beforeAfter := beforeAfter{} + + err := mapstructure.Decode(data, &beforeAfter) + if err != nil { + return err + } + + userBeforeAfter := beforeAfter.UserBeforeAfter() switch { - case diff.before == diff.after: + case userBeforeAfter.before == userBeforeAfter.after: return nil - case diff.before == (user.User{}): - return p.creator.Create(ctx, diff.after) + case userBeforeAfter.before == (user.User{}): + return p.creator.Create(ctx, userBeforeAfter.after) default: return errors.New("not implemented") } } -// userBeforeAfter converts the inputData to map[string]user.User. -// -// The CreatedAt timestamp (io.debezium.time.Timestamp) is an int64 that represents the unix -// timestamp in msec. As the first arg to time.Unix is expected to be sec, the CreatedAt -// value needs to be divided by 1000. The second arg to time.Unix is nsec, so the msec that -// remain after the sec are subtracted are multiplied by 1000000. -func (p *p) userBeforeAfter(inputData inputData) userChange { - msecToTime := func(msec int64) time.Time { - const ( - divisor = 1e3 - multiplier = 1e6 - ) +type beforeAfter struct { + Before value + After value +} - t := time.Time{} +type value struct { + Value usr `mapstructure:"mysql.go_api_demo.users.Value"` +} - if msec > 0 { - sec := msec / divisor - nsec := (msec - (sec * divisor)) * multiplier - t = time.Unix(sec, nsec) - } +type usr struct { + ID string `mapstructure:"id"` + FirstName string `mapstructure:"first_name"` + LastName string `mapstructure:"last_name"` + CreatedAt int64 `mapstructure:"created_at"` +} - return t - } +type userBeforeAfter struct { + before user.User + after user.User +} - return userChange{ +// UserBeforeAfter converts beforeAfter to struct +// containing user.User for before and after. +// +// The CreatedAt timestamp (io.debezium.time.Timestamp) is an +// int64 that represents the unix timestamp in msec. +func (bf beforeAfter) UserBeforeAfter() userBeforeAfter { + return userBeforeAfter{ before: user.User{ - CreatedAt: msecToTime(inputData.Before.CreatedAt), - ID: inputData.Before.ID, - FirstName: inputData.Before.FirstName, - LastName: inputData.Before.LastName, + CreatedAt: format.MsecToTime(bf.Before.Value.CreatedAt), + ID: bf.Before.Value.ID, + FirstName: bf.Before.Value.FirstName, + LastName: bf.Before.Value.LastName, }, after: user.User{ - CreatedAt: msecToTime(inputData.After.CreatedAt), - ID: inputData.After.ID, - FirstName: inputData.After.FirstName, - LastName: inputData.After.LastName, + CreatedAt: format.MsecToTime(bf.After.Value.CreatedAt), + ID: bf.After.Value.ID, + FirstName: bf.After.Value.FirstName, + LastName: bf.After.Value.LastName, }, } } - -type userChange struct { - before user.User - after user.User -} diff --git a/internal/user/consume/processor_test.go b/internal/user/consume/processor_test.go index 710d4af..0ba9ca6 100644 --- a/internal/user/consume/processor_test.go +++ b/internal/user/consume/processor_test.go @@ -3,72 +3,214 @@ package consume import ( "context" "errors" + "fmt" "testing" "github.com/bendbennett/go-api-demo/internal/user" + "github.com/mitchellh/mapstructure" "github.com/stretchr/testify/assert" ) -type creatorMockError struct { -} - -func (m *creatorMockError) Create(context.Context, ...user.User) error { - return errors.New("creator create error") -} - type creatorMock struct { + hasBeenCalled bool } func (m *creatorMock) Create(context.Context, ...user.User) error { + m.hasBeenCalled = true return nil } +func (m *creatorMock) HasBeenCalled() bool { + return m.hasBeenCalled +} + +// TODO: Test should confirm that Create() is called on creatorMock +// when before == empty user func TestProcessor_Process(t *testing.T) { - cases := []struct { - name string - creator user.Creator - inputData inputData - returnsErr bool + cases := map[string]struct { + creator *creatorMock + data any + creatorHasBeenCalled bool + expectedErr error }{ - { - "creator returns error", - &creatorMockError{}, - inputData{ - After: usr{ID: "id"}, + "no processing required": { + &creatorMock{}, + map[string]interface{}{ + "after": map[string]interface{}{ + "mysql.go_api_demo.users.Value": map[string]interface{}{ + "id": "1", + }, + }, + "before": map[string]interface{}{ + "mysql.go_api_demo.users.Value": map[string]interface{}{ + "id": "1", + }, + }, }, - true, + false, + nil, }, - { - "unimplemented processing", + "create called": { &creatorMock{}, - inputData{ - Before: usr{ID: "id"}, + map[string]interface{}{ + "after": map[string]interface{}{ + "mysql.go_api_demo.users.Value": map[string]interface{}{ + "id": "1", + }, + }, + "before": nil, }, true, + nil, }, - { - "success", + "unimplemented error": { &creatorMock{}, - inputData{}, + map[string]interface{}{ + "after": nil, + "before": map[string]interface{}{ + "mysql.go_api_demo.users.Value": map[string]interface{}{ + "id": "1", + }, + }, + }, false, + errors.New("not implemented"), }, } - for _, c := range cases { - t.Run(c.name, func(t *testing.T) { + for name, c := range cases { + t.Run(name, func(t *testing.T) { processor := NewProcessor( c.creator, ) + err := processor.Process( context.Background(), - c.inputData, + c.data, ) - if c.returnsErr { - assert.Error(t, err) - } else { - assert.NoError(t, err) - } + assert.Equal(t, c.creatorHasBeenCalled, c.creator.HasBeenCalled()) + assert.Equal(t, c.expectedErr, err) }) } } + +var msg = map[string]interface{}{ + "after": map[string]interface{}{ + "go_api_demo_db.go_api_demo.users.Value": map[string]interface{}{ + "created_at": 1639512014000, + "first_name": "john", + "id": "673b3c8c-3589-4b77-af89-94dcda52a861", + "last_name": "smith", + }, + }, + "before": nil, + "op": "c", + "source": map[string]interface{}{ + "connector": "mysql", + "db": "go-api-demo", + "file": "binlog.000002", + "gtid": nil, + "name": "go_api_demo_db", + "pos": 9548, + "query": nil, + "row": 0, + "sequence": nil, + "server_id": 1, + "snapshot": map[string]interface{}{ + "string": "false", + }, + "table": map[string]interface{}{ + "string": "users", + }, + "thread": nil, + "ts_ms": 1639512013000, + "version": "1.7.1.Final", + }, + "transaction": nil, + "ts_ms": map[string]interface{}{ + "long": 1639512013850, + }, +} + +// nolint:gocyclo +func Benchmark_Extract(b *testing.B) { + extractUser := func(msg interface{}, key string) (usr, error) { + valKey := "go_api_demo_db.go_api_demo.users.Value" + + if _, ok := msg.(map[string]interface{}); !ok { + return usr{}, errors.New("cannot assert msg as map[string]interface{}") + } + + m := msg.(map[string]interface{}) + + if _, ok := m[key]; !ok { + return usr{}, fmt.Errorf("%v key missing from msg", key) + } + + if m[key] == nil { + return usr{}, nil + } + + if _, ok := m[key].(map[string]interface{}); !ok { + return usr{}, fmt.Errorf("cannot assert msg[%v] as map[string]interface{}", key) + } + + m = m[key].(map[string]interface{}) + + if _, ok := m[valKey]; !ok { + return usr{}, fmt.Errorf("%v key missing from msg", valKey) + } + + if _, ok := m[valKey].(map[string]interface{}); !ok { + return usr{}, fmt.Errorf("cannot assert msg[%v][%v] as map[string]interface{}", key, valKey) + } + + m = m[valKey].(map[string]interface{}) + + reqKeys := []string{"id", "first_name", "last_name", "created_at"} + + for _, reqKey := range reqKeys { + if _, ok := m[reqKey]; !ok { + return usr{}, fmt.Errorf("%v key missing from msg", reqKey) + } + } + + if _, ok := m["id"].(string); !ok { + return usr{}, errors.New("cannot assert id is string") + } + + if _, ok := m["first_name"].(string); !ok { + return usr{}, errors.New("cannot assert first_name is string") + } + + if _, ok := m["last_name"].(string); !ok { + return usr{}, errors.New("cannot assert last_name is string") + } + + if _, ok := m["created_at"].(int64); !ok { + return usr{}, errors.New("cannot assert created_at is int64") + } + + return usr{ + ID: m["id"].(string), + FirstName: m["first_name"].(string), + LastName: m["last_name"].(string), + CreatedAt: m["created_at"].(int64), + }, nil + } + + for n := 0; n < b.N; n++ { + _, _ = extractUser(msg, "after") + + } +} + +func Benchmark_MapExtract(b *testing.B) { + m := beforeAfter{} + + for n := 0; n < b.N; n++ { + _ = mapstructure.Decode(msg, &m) + + } +} diff --git a/test/e2e_test.go b/test/e2e_test.go index 5b295d3..dc93fa9 100644 --- a/test/e2e_test.go +++ b/test/e2e_test.go @@ -6,7 +6,7 @@ import ( "database/sql" "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "os" "strings" @@ -14,24 +14,25 @@ import ( "testing" "time" - "github.com/elastic/go-elasticsearch/v7" - "github.com/elastic/go-elasticsearch/v7/esapi" + "github.com/elastic/go-elasticsearch/v8" + "github.com/elastic/go-elasticsearch/v8/esapi" "github.com/joho/godotenv" - "github.com/go-redis/redis/v8" + "github.com/redis/go-redis/v9" user "github.com/bendbennett/go-api-demo/generated" "github.com/bendbennett/go-api-demo/internal/bootstrap" "github.com/bendbennett/go-api-demo/internal/config" "github.com/bendbennett/go-api-demo/internal/validate" _ "github.com/go-sql-driver/mysql" - "github.com/golang-migrate/migrate" - migratemysql "github.com/golang-migrate/migrate/database/mysql" - _ "github.com/golang-migrate/migrate/source/file" + "github.com/golang-migrate/migrate/v4" + migratemysql "github.com/golang-migrate/migrate/v4/database/mysql" + _ "github.com/golang-migrate/migrate/v4/source/file" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "golang.org/x/sync/errgroup" "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" ) func Test_E2E(t *testing.T) { @@ -70,9 +71,8 @@ func env(t *testing.T) { env := map[string]string{ "HTTP_PORT": "3001", "GRPC_PORT": "1235", - "TRACING_ENABLED": "false", + "TELEMETRY_ENABLED": "false", "LOGGING_PRODUCTION": "true", - "METRICS_ENABLED": "false", } for k, v := range env { @@ -95,7 +95,7 @@ func purge(t *testing.T) { db, err := sql.Open( "mysql", fmt.Sprintf( - "%s:%s@tcp(%s:%s)/%s?parseTime=true", + "%s:%s@tcp(%s:%s)/%s?parseTime=true&multiStatements=true", config.GetEnvAsString("MYSQL_USER", ""), config.GetEnvAsString("MYSQL_PASSWORD", ""), config.GetEnvAsString("MYSQL_HOST", ""), @@ -125,6 +125,25 @@ func purge(t *testing.T) { t.Error(err) } + // WithInstance calls WithConnection which ensures that the schema migrations table + // is created if it does not exist. Hence WithInstance needs to be called + // again after calling Drop so that schema_migrations table is recreated after drop. + // + // https://github.com/golang-migrate/migrate/issues/226 + dbInstance, err = migratemysql.WithInstance(db, &migratemysql.Config{}) + if err != nil { + panic(err) + } + + m, err = migrate.NewWithDatabaseInstance( + "file://../internal/storage/mysql/migrations", + "mysql", + dbInstance, + ) + if err != nil { + t.Error(err) + } + if err := m.Up(); err != nil && err != migrate.ErrNoChange { t.Error(err) } @@ -271,7 +290,7 @@ func (a *httpClient) doRequest(payload httpRequest) (int, []byte, error) { } defer resp.Body.Close() - bodyBytes, err := ioutil.ReadAll(resp.Body) + bodyBytes, err := io.ReadAll(resp.Body) if err != nil { return 0, nil, fmt.Errorf("body read err: %v", err) } @@ -457,8 +476,7 @@ type grpcClient struct { } func newGRPCClient() *grpcClient { - conn, err := grpc.DialContext( - context.Background(), + conn, err := grpc.NewClient( fmt.Sprintf( "%s:%d", config.GetEnvAsString( @@ -470,7 +488,9 @@ func newGRPCClient() *grpcClient { 1235, ), ), - grpc.WithInsecure(), + grpc.WithTransportCredentials( + insecure.NewCredentials(), + ), ) if err != nil { panic(err)