diff --git a/.circleci/config.yml b/.circleci/config.yml index 219f765f..dbe6ca37 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,12 +1,12 @@ --- version: 2.1 orbs: - prometheus: prometheus/prometheus@0.16.0 + prometheus: prometheus/prometheus@0.17.1 executors: # This must match .promu.yml. golang: docker: - - image: cimg/go:1.18 + - image: cimg/go:1.20 jobs: test: executor: golang diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 136d7d4b..433f71b8 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -1,3 +1,5 @@ +--- +# This action is synced from https://github.com/prometheus/prometheus name: golangci-lint on: push: @@ -18,13 +20,13 @@ jobs: - name: Checkout repository uses: actions/checkout@v3 - name: install Go - uses: actions/setup-go@v2 + uses: actions/setup-go@v3 with: - go-version: 1.18.x + go-version: 1.20.x - name: Install snmp_exporter/generator dependencies run: sudo apt-get update && sudo apt-get -y install libsnmp-dev if: github.repository == 'prometheus/snmp_exporter' - name: Lint - uses: golangci/golangci-lint-action@v3.1.0 + uses: golangci/golangci-lint-action@v3.4.0 with: - version: v1.45.2 + version: v1.53.3 diff --git a/.golangci.yml b/.golangci.yml index 58af0229..2d8a26d5 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -8,3 +8,7 @@ issues: - path: _test.go linters: - errcheck + +linters-settings: + errcheck: + exclude: scripts/errcheck_excludes.txt diff --git a/.promu.yml b/.promu.yml index 9f6d8a0d..027bf9e6 100644 --- a/.promu.yml +++ b/.promu.yml @@ -1,6 +1,6 @@ go: # This must match .circle/config.yml. - version: 1.18 + version: 1.20 repository: path: github.com/prometheus-community/elasticsearch_exporter build: diff --git a/.yamllint b/.yamllint index 3878a31d..955a5a62 100644 --- a/.yamllint +++ b/.yamllint @@ -20,9 +20,4 @@ rules: config/testdata/section_key_dup.bad.yml line-length: disable truthy: - ignore: | - .github/workflows/codeql-analysis.yml - .github/workflows/funcbench.yml - .github/workflows/fuzzing.yml - .github/workflows/prombench.yml - .github/workflows/golangci-lint.yml + check-keys: false diff --git a/CHANGELOG.md b/CHANGELOG.md index bfe19778..1cb10b4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,35 @@ +## 1.6.0 / 2023-06-22 + +BREAKING CHANGES: + +The flag `--es.cluster_settings` has been renamed to `--collector.clustersettings`. + +* [CHANGE] Rename --es.cluster_settings to --collector.clustersettings +* [FEATURE] Add ILM metrics #513 +* [ENHANCEMENT] Add ElasticCloud node roles to role label #652 +* [ENHANCEMENT] Add ability to use AWS IAM role for authentication #653 +* [ENHANCEMENT] Add metric for index replica count #483 +* [BUGFIX] Set elasticsearch_clusterinfo_version_info guage to 1 #728 +* [BUGFIX] Fix index field counts with nested fields #675 + + +## 1.5.0 / 2022-07-28 + +* [FEATURE] Add metrics collection for data stream statistics #592 +* [FEATURE] Support for AWS Elasticsearch using AWS SDK v2 #597 +* [BUGFIX] Fix cluster settings collection when max_shards_per_node is manually set. #603 + +## 1.4.0 / 2022-06-29 + +* [BREAKING] Remove ENV var support for most non-sensitive options. #518 +* [BREAKING] Rename elasticsearch_process_cpu_time_seconds_sum to elasticsearch_process_cpu_seconds_total #520 +* [FEATURE] Add metric for index aliases #563 +* [FEATURE] Add metric for number of shards on a node #535 +* [FEATURE] Add metrics for SLM (snapshot lifecycle management) #558 +* [FEATURE] Add metric for JVM uptime #537 +* [FEATURE] Add metrics for current searches and current indexing documents #485 +* [BUGFIX] Remove the elasticsearch_process_cpu_time_seconds_sum metric as it was never used #498 + ## 1.3.0 / 2021-10-21 * [FEATURE] Add support for passing elasticsearch credentials via the ES_USERNAME and ES_PASSWORD environment varialbes #461 diff --git a/Makefile.common b/Makefile.common index c263b733..0ce7ea46 100644 --- a/Makefile.common +++ b/Makefile.common @@ -36,29 +36,6 @@ GO_VERSION ?= $(shell $(GO) version) GO_VERSION_NUMBER ?= $(word 3, $(GO_VERSION)) PRE_GO_111 ?= $(shell echo $(GO_VERSION_NUMBER) | grep -E 'go1\.(10|[0-9])\.') -GOVENDOR := -GO111MODULE := -ifeq (, $(PRE_GO_111)) - ifneq (,$(wildcard go.mod)) - # Enforce Go modules support just in case the directory is inside GOPATH (and for Travis CI). - GO111MODULE := on - - ifneq (,$(wildcard vendor)) - # Always use the local vendor/ directory to satisfy the dependencies. - GOOPTS := $(GOOPTS) -mod=vendor - endif - endif -else - ifneq (,$(wildcard go.mod)) - ifneq (,$(wildcard vendor)) -$(warning This repository requires Go >= 1.11 because of Go modules) -$(warning Some recipes may not work as expected as the current Go runtime is '$(GO_VERSION_NUMBER)') - endif - else - # This repository isn't using Go modules (yet). - GOVENDOR := $(FIRST_GOPATH)/bin/govendor - endif -endif PROMU := $(FIRST_GOPATH)/bin/promu pkgs = ./... @@ -72,25 +49,28 @@ endif GOTEST := $(GO) test GOTEST_DIR := ifneq ($(CIRCLE_JOB),) -ifneq ($(shell which gotestsum),) +ifneq ($(shell command -v gotestsum > /dev/null),) GOTEST_DIR := test-results GOTEST := gotestsum --junitfile $(GOTEST_DIR)/unit-tests.xml -- endif endif -PROMU_VERSION ?= 0.13.0 +PROMU_VERSION ?= 0.15.0 PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_VERSION)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM).tar.gz +SKIP_GOLANGCI_LINT := GOLANGCI_LINT := GOLANGCI_LINT_OPTS ?= -GOLANGCI_LINT_VERSION ?= v1.45.2 +GOLANGCI_LINT_VERSION ?= v1.53.3 # golangci-lint only supports linux, darwin and windows platforms on i386/amd64. # windows isn't included here because of the path separator being different. ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin)) ifeq ($(GOHOSTARCH),$(filter $(GOHOSTARCH),amd64 i386)) # If we're in CI and there is an Actions file, that means the linter # is being run in Actions, so we don't need to run it here. - ifeq (,$(CIRCLE_JOB)) + ifneq (,$(SKIP_GOLANGCI_LINT)) + GOLANGCI_LINT := + else ifeq (,$(CIRCLE_JOB)) GOLANGCI_LINT := $(FIRST_GOPATH)/bin/golangci-lint else ifeq (,$(wildcard .github/workflows/golangci-lint.yml)) GOLANGCI_LINT := $(FIRST_GOPATH)/bin/golangci-lint @@ -111,6 +91,8 @@ BUILD_DOCKER_ARCHS = $(addprefix common-docker-,$(DOCKER_ARCHS)) PUBLISH_DOCKER_ARCHS = $(addprefix common-docker-publish-,$(DOCKER_ARCHS)) TAG_DOCKER_ARCHS = $(addprefix common-docker-tag-latest-,$(DOCKER_ARCHS)) +SANITIZED_DOCKER_IMAGE_TAG := $(subst +,-,$(DOCKER_IMAGE_TAG)) + ifeq ($(GOHOSTARCH),amd64) ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux freebsd darwin windows)) # Only supported on amd64 @@ -150,11 +132,7 @@ common-check_license: .PHONY: common-deps common-deps: @echo ">> getting dependencies" -ifdef GO111MODULE - GO111MODULE=$(GO111MODULE) $(GO) mod download -else - $(GO) get $(GOOPTS) -t ./... -endif + $(GO) mod download .PHONY: update-go-deps update-go-deps: @@ -162,20 +140,17 @@ update-go-deps: @for m in $$($(GO) list -mod=readonly -m -f '{{ if and (not .Indirect) (not .Main)}}{{.Path}}{{end}}' all); do \ $(GO) get -d $$m; \ done - GO111MODULE=$(GO111MODULE) $(GO) mod tidy -ifneq (,$(wildcard vendor)) - GO111MODULE=$(GO111MODULE) $(GO) mod vendor -endif + $(GO) mod tidy .PHONY: common-test-short common-test-short: $(GOTEST_DIR) @echo ">> running short tests" - GO111MODULE=$(GO111MODULE) $(GOTEST) -short $(GOOPTS) $(pkgs) + $(GOTEST) -short $(GOOPTS) $(pkgs) .PHONY: common-test common-test: $(GOTEST_DIR) @echo ">> running all tests" - GO111MODULE=$(GO111MODULE) $(GOTEST) $(test-flags) $(GOOPTS) $(pkgs) + $(GOTEST) $(test-flags) $(GOOPTS) $(pkgs) $(GOTEST_DIR): @mkdir -p $@ @@ -183,31 +158,27 @@ $(GOTEST_DIR): .PHONY: common-format common-format: @echo ">> formatting code" - GO111MODULE=$(GO111MODULE) $(GO) fmt $(pkgs) + $(GO) fmt $(pkgs) .PHONY: common-vet common-vet: @echo ">> vetting code" - GO111MODULE=$(GO111MODULE) $(GO) vet $(GOOPTS) $(pkgs) + $(GO) vet $(GOOPTS) $(pkgs) .PHONY: common-lint common-lint: $(GOLANGCI_LINT) ifdef GOLANGCI_LINT @echo ">> running golangci-lint" -ifdef GO111MODULE # 'go list' needs to be executed before staticcheck to prepopulate the modules cache. # Otherwise staticcheck might fail randomly for some reason not yet explained. - GO111MODULE=$(GO111MODULE) $(GO) list -e -compiled -test=true -export=false -deps=true -find=false -tags= -- ./... > /dev/null - GO111MODULE=$(GO111MODULE) $(GOLANGCI_LINT) run $(GOLANGCI_LINT_OPTS) $(pkgs) -else - $(GOLANGCI_LINT) run $(pkgs) -endif + $(GO) list -e -compiled -test=true -export=false -deps=true -find=false -tags= -- ./... > /dev/null + $(GOLANGCI_LINT) run $(GOLANGCI_LINT_OPTS) $(pkgs) endif .PHONY: common-yamllint common-yamllint: @echo ">> running yamllint on all YAML files in the repository" -ifeq (, $(shell which yamllint)) +ifeq (, $(shell command -v yamllint > /dev/null)) @echo "yamllint not installed so skipping" else yamllint . @@ -218,28 +189,15 @@ endif common-staticcheck: lint .PHONY: common-unused -common-unused: $(GOVENDOR) -ifdef GOVENDOR - @echo ">> running check for unused packages" - @$(GOVENDOR) list +unused | grep . && exit 1 || echo 'No unused packages' -else -ifdef GO111MODULE +common-unused: @echo ">> running check for unused/missing packages in go.mod" - GO111MODULE=$(GO111MODULE) $(GO) mod tidy -ifeq (,$(wildcard vendor)) + $(GO) mod tidy @git diff --exit-code -- go.sum go.mod -else - @echo ">> running check for unused packages in vendor/" - GO111MODULE=$(GO111MODULE) $(GO) mod vendor - @git diff --exit-code -- go.sum go.mod vendor/ -endif -endif -endif .PHONY: common-build common-build: promu @echo ">> building binaries" - GO111MODULE=$(GO111MODULE) $(PROMU) build --prefix $(PREFIX) $(PROMU_BINARIES) + $(PROMU) build --prefix $(PREFIX) $(PROMU_BINARIES) .PHONY: common-tarball common-tarball: promu @@ -249,7 +207,7 @@ common-tarball: promu .PHONY: common-docker $(BUILD_DOCKER_ARCHS) common-docker: $(BUILD_DOCKER_ARCHS) $(BUILD_DOCKER_ARCHS): common-docker-%: - docker build -t "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" \ + docker build -t "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)" \ -f $(DOCKERFILE_PATH) \ --build-arg ARCH="$*" \ --build-arg OS="linux" \ @@ -258,19 +216,19 @@ $(BUILD_DOCKER_ARCHS): common-docker-%: .PHONY: common-docker-publish $(PUBLISH_DOCKER_ARCHS) common-docker-publish: $(PUBLISH_DOCKER_ARCHS) $(PUBLISH_DOCKER_ARCHS): common-docker-publish-%: - docker push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" + docker push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)" DOCKER_MAJOR_VERSION_TAG = $(firstword $(subst ., ,$(shell cat VERSION))) .PHONY: common-docker-tag-latest $(TAG_DOCKER_ARCHS) common-docker-tag-latest: $(TAG_DOCKER_ARCHS) $(TAG_DOCKER_ARCHS): common-docker-tag-latest-%: - docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:latest" - docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:v$(DOCKER_MAJOR_VERSION_TAG)" + docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:latest" + docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:v$(DOCKER_MAJOR_VERSION_TAG)" .PHONY: common-docker-manifest common-docker-manifest: - DOCKER_CLI_EXPERIMENTAL=enabled docker manifest create -a "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)" $(foreach ARCH,$(DOCKER_ARCHS),$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$(ARCH):$(DOCKER_IMAGE_TAG)) - DOCKER_CLI_EXPERIMENTAL=enabled docker manifest push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)" + DOCKER_CLI_EXPERIMENTAL=enabled docker manifest create -a "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(SANITIZED_DOCKER_IMAGE_TAG)" $(foreach ARCH,$(DOCKER_ARCHS),$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$(ARCH):$(SANITIZED_DOCKER_IMAGE_TAG)) + DOCKER_CLI_EXPERIMENTAL=enabled docker manifest push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(SANITIZED_DOCKER_IMAGE_TAG)" .PHONY: promu promu: $(PROMU) @@ -295,12 +253,6 @@ $(GOLANGCI_LINT): | sh -s -- -b $(FIRST_GOPATH)/bin $(GOLANGCI_LINT_VERSION) endif -ifdef GOVENDOR -.PHONY: $(GOVENDOR) -$(GOVENDOR): - GOOS= GOARCH= $(GO) get -u github.com/kardianos/govendor -endif - .PHONY: precheck precheck:: diff --git a/README.md b/README.md index a1cf9104..4d22d104 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,14 @@ # Elasticsearch Exporter + [![CircleCI](https://circleci.com/gh/prometheus-community/elasticsearch_exporter.svg?style=svg)](https://circleci.com/gh/prometheus-community/elasticsearch_exporter) [![Go Report Card](https://goreportcard.com/badge/github.com/prometheus-community/elasticsearch_exporter)](https://goreportcard.com/report/github.com/prometheus-community/elasticsearch_exporter) -Prometheus exporter for various metrics about ElasticSearch, written in Go. +Prometheus exporter for various metrics about Elasticsearch, written in Go. ### Installation For pre-built binaries please take a look at the releases. -https://github.com/prometheus-community/elasticsearch_exporter/releases + #### Docker @@ -30,7 +31,7 @@ elasticsearch_exporter: #### Kubernetes -You can find a helm chart in the prometheus-community charts repository at https://github.com/prometheus-community/helm-charts/tree/main/charts/prometheus-elasticsearch-exporter +You can find a helm chart in the prometheus-community charts repository at ```bash helm repo add prometheus-community https://prometheus-community.github.io/helm-charts @@ -39,24 +40,27 @@ helm install [RELEASE_NAME] prometheus-community/prometheus-elasticsearch-export ### Configuration -**NOTE:** The exporter fetches information from an ElasticSearch cluster on every scrape, therefore having a too short scrape interval can impose load on ES master nodes, particularly if you run with `--es.all` and `--es.indices`. We suggest you measure how long fetching `/_nodes/stats` and `/_all/_stats` takes for your ES cluster to determine whether your scraping interval is too short. As a last resort, you can scrape this exporter using a dedicated job with its own scraping interval. +**NOTE:** The exporter fetches information from an Elasticsearch cluster on every scrape, therefore having a too short scrape interval can impose load on ES master nodes, particularly if you run with `--es.all` and `--es.indices`. We suggest you measure how long fetching `/_nodes/stats` and `/_all/_stats` takes for your ES cluster to determine whether your scraping interval is too short. As a last resort, you can scrape this exporter using a dedicated job with its own scraping interval. Below is the command line options summary: + ```bash elasticsearch_exporter --help ``` | Argument | Introduced in Version | Description | Default | -| -------- | --------------------- | ----------- | ----------- | -| es.uri | 1.0.2 | Address (host and port) of the Elasticsearch node we should connect to. This could be a local node (`localhost:9200`, for instance), or the address of a remote Elasticsearch server. When basic auth is needed, specify as: `://:@:`. E.G., `http://admin:pass@localhost:9200`. Special characters in the user credentials need to be URL-encoded. | http://localhost:9200 | +| ----------------------- | --------------------- | ----------- | ----------- | +| es.uri | 1.0.2 | Address (host and port) of the Elasticsearch node we should connect to. This could be a local node (`localhost:9200`, for instance), or the address of a remote Elasticsearch server. When basic auth is needed, specify as: `://:@:`. E.G., `http://admin:pass@localhost:9200`. Special characters in the user credentials need to be URL-encoded. | | | es.all | 1.0.2 | If true, query stats for all nodes in the cluster, rather than just the node we connect to. | false | | es.cluster_settings | 1.1.0rc1 | If true, query stats for cluster settings. | false | | es.indices | 1.0.2 | If true, query stats for all indices in the cluster. | false | | es.indices_settings | 1.0.4rc1 | If true, query settings stats for all indices in the cluster. | false | | es.indices_mappings | 1.2.0 | If true, query stats for mappings of all indices of the cluster. | false | +| es.aliases | 1.0.4rc1 | If true, include informational aliases metrics. | true | | es.shards | 1.0.3rc1 | If true, query stats for all indices in the cluster, including shard-level stats (implies `es.indices=true`). | false | | es.snapshots | 1.0.4rc1 | If true, query stats for the cluster snapshots. | false | | es.slm | | If true, query stats for SLM. | false | +| es.data_stream | | If true, query state for Data Steams. | false | | es.timeout | 1.0.2 | Timeout for trying to get stats from Elasticsearch. (ex: 20s) | 5s | | es.ca | 1.0.2 | Path to PEM file that contains trusted Certificate Authorities for the Elasticsearch connection. | | | es.client-private-key | 1.0.2 | Path to PEM file that contains the private key for client auth when connecting to Elasticsearch. | | @@ -65,6 +69,8 @@ elasticsearch_exporter --help | es.ssl-skip-verify | 1.0.4rc1 | Skip SSL verification when connecting to Elasticsearch. | false | | web.listen-address | 1.0.2 | Address to listen on for web interface and telemetry. | :9114 | | web.telemetry-path | 1.0.2 | Path under which to expose metrics. | /metrics | +| aws.region | 1.5.0 | Region for AWS elasticsearch | | +| aws.role-arn | 1.6.0 | Role ARN of an IAM role to assume. | | | version | 1.0.2 | Show version info on stdout and exit. | | Commandline parameters start with a single `-` for versions less than `1.1.0rc1`. @@ -85,167 +91,184 @@ exporter defaults | `cluster` `monitor` | All cluster read-only operations, like es.cluster_settings | `cluster` `monitor` | es.indices | `indices` `monitor` (per index or `*`) | All actions that are required for monitoring (recovery, segments info, index stats and status) es.indices_settings | `indices` `monitor` (per index or `*`) | +es.indices_mappings | `indices` `view_index_metadata` (per index or `*`) | es.shards | not sure if `indices` or `cluster` `monitor` or both | es.snapshots | `cluster:admin/snapshot/status` and `cluster:admin/repository/get` | [ES Forum Post](https://discuss.elastic.co/t/permissions-for-backup-user-with-x-pack/88057) es.slm | `read_slm` +es.data_stream | `monitor` or `manage` (per index or `*`) | Further Information -- [Build in Users](https://www.elastic.co/guide/en/elastic-stack-overview/7.3/built-in-users.html) + +- [Built in Users](https://www.elastic.co/guide/en/elastic-stack-overview/7.3/built-in-users.html) - [Defining Roles](https://www.elastic.co/guide/en/elastic-stack-overview/7.3/defining-roles.html) - [Privileges](https://www.elastic.co/guide/en/elastic-stack-overview/7.3/security-privileges.html) ### Metrics -|Name |Type |Cardinality |Help -|---- |---- |----------- |---- -| elasticsearch_breakers_estimated_size_bytes | gauge | 4 | Estimated size in bytes of breaker -| elasticsearch_breakers_limit_size_bytes | gauge | 4 | Limit size in bytes for breaker -| elasticsearch_breakers_tripped | counter | 4 | tripped for breaker -| elasticsearch_cluster_health_active_primary_shards | gauge | 1 | The number of primary shards in your cluster. This is an aggregate total across all indices. -| elasticsearch_cluster_health_active_shards | gauge | 1 | Aggregate total of all shards across all indices, which includes replica shards. -| elasticsearch_cluster_health_delayed_unassigned_shards | gauge | 1 | Shards delayed to reduce reallocation overhead -| elasticsearch_cluster_health_initializing_shards | gauge | 1 | Count of shards that are being freshly created. -| elasticsearch_cluster_health_number_of_data_nodes | gauge | 1 | Number of data nodes in the cluster. -| elasticsearch_cluster_health_number_of_in_flight_fetch | gauge | 1 | The number of ongoing shard info requests. -| elasticsearch_cluster_health_number_of_nodes | gauge | 1 | Number of nodes in the cluster. -| elasticsearch_cluster_health_number_of_pending_tasks | gauge | 1 | Cluster level changes which have not yet been executed -| elasticsearch_cluster_health_task_max_waiting_in_queue_millis | gauge | 1 | Max time in millis that a task is waiting in queue. -| elasticsearch_cluster_health_relocating_shards | gauge | 1 | The number of shards that are currently moving from one node to another node. -| elasticsearch_cluster_health_status | gauge | 3 | Whether all primary and replica shards are allocated. -| elasticsearch_cluster_health_timed_out | gauge | 1 | Number of cluster health checks timed out -| elasticsearch_cluster_health_unassigned_shards | gauge | 1 | The number of shards that exist in the cluster state, but cannot be found in the cluster itself. -| elasticsearch_clustersettings_stats_max_shards_per_node | gauge | 0 | Current maximum number of shards per node setting. -| elasticsearch_filesystem_data_available_bytes | gauge | 1 | Available space on block device in bytes -| elasticsearch_filesystem_data_free_bytes | gauge | 1 | Free space on block device in bytes -| elasticsearch_filesystem_data_size_bytes | gauge | 1 | Size of block device in bytes -| elasticsearch_filesystem_io_stats_device_operations_count | gauge | 1 | Count of disk operations -| elasticsearch_filesystem_io_stats_device_read_operations_count | gauge | 1 | Count of disk read operations -| elasticsearch_filesystem_io_stats_device_write_operations_count | gauge | 1 | Count of disk write operations -| elasticsearch_filesystem_io_stats_device_read_size_kilobytes_sum | gauge | 1 | Total kilobytes read from disk -| elasticsearch_filesystem_io_stats_device_write_size_kilobytes_sum | gauge | 1 | Total kilobytes written to disk -| elasticsearch_indices_active_queries | gauge | 1 | The number of currently active queries -| elasticsearch_indices_docs | gauge | 1 | Count of documents on this node -| elasticsearch_indices_docs_deleted | gauge | 1 | Count of deleted documents on this node -| elasticsearch_indices_docs_primary | gauge | | Count of documents with only primary shards on all nodes -| elasticsearch_indices_fielddata_evictions | counter | 1 | Evictions from field data -| elasticsearch_indices_fielddata_memory_size_bytes | gauge | 1 | Field data cache memory usage in bytes -| elasticsearch_indices_filter_cache_evictions | counter | 1 | Evictions from filter cache -| elasticsearch_indices_filter_cache_memory_size_bytes | gauge | 1 | Filter cache memory usage in bytes -| elasticsearch_indices_flush_time_seconds | counter | 1 | Cumulative flush time in seconds -| elasticsearch_indices_flush_total | counter | 1 | Total flushes -| elasticsearch_indices_get_exists_time_seconds | counter | 1 | Total time get exists in seconds -| elasticsearch_indices_get_exists_total | counter | 1 | Total get exists operations -| elasticsearch_indices_get_missing_time_seconds | counter | 1 | Total time of get missing in seconds -| elasticsearch_indices_get_missing_total | counter | 1 | Total get missing -| elasticsearch_indices_get_time_seconds | counter | 1 | Total get time in seconds -| elasticsearch_indices_get_total | counter | 1 | Total get -| elasticsearch_indices_indexing_delete_time_seconds_total | counter | 1 | Total time indexing delete in seconds -| elasticsearch_indices_indexing_delete_total | counter | 1 | Total indexing deletes -| elasticsearch_indices_index_current | gauge | 1 | The number of documents currently being indexed to an index -| elasticsearch_indices_indexing_index_time_seconds_total | counter | 1 | Cumulative index time in seconds -| elasticsearch_indices_indexing_index_total | counter | 1 | Total index calls -| elasticsearch_indices_mappings_stats_fields | gauge | 1 | Count of fields currently mapped by index -| elasticsearch_indices_mappings_stats_json_parse_failures_total | counter | 0 | Number of errors while parsing JSON -| elasticsearch_indices_mappings_stats_scrapes_total | counter | 0 | Current total ElasticSearch Indices Mappings scrapes -| elasticsearch_indices_mappings_stats_up | gauge | 0 | Was the last scrape of the ElasticSearch Indices Mappings endpoint successful -| elasticsearch_indices_merges_docs_total | counter | 1 | Cumulative docs merged -| elasticsearch_indices_merges_total | counter | 1 | Total merges -| elasticsearch_indices_merges_total_size_bytes_total | counter | 1 | Total merge size in bytes -| elasticsearch_indices_merges_total_time_seconds_total | counter | 1 | Total time spent merging in seconds -| elasticsearch_indices_query_cache_cache_total | counter | 1 | Count of query cache -| elasticsearch_indices_query_cache_cache_size | gauge | 1 | Size of query cache -| elasticsearch_indices_query_cache_count | counter | 2 | Count of query cache hit/miss -| elasticsearch_indices_query_cache_evictions | counter | 1 | Evictions from query cache -| elasticsearch_indices_query_cache_memory_size_bytes | gauge | 1 | Query cache memory usage in bytes -| elasticsearch_indices_query_cache_total | counter | 1 | Size of query cache total -| elasticsearch_indices_refresh_time_seconds_total | counter | 1 | Total time spent refreshing in seconds -| elasticsearch_indices_refresh_total | counter | 1 | Total refreshes -| elasticsearch_indices_request_cache_count | counter | 2 | Count of request cache hit/miss -| elasticsearch_indices_request_cache_evictions | counter | 1 | Evictions from request cache -| elasticsearch_indices_request_cache_memory_size_bytes | gauge | 1 | Request cache memory usage in bytes -| elasticsearch_indices_search_fetch_time_seconds | counter | 1 | Total search fetch time in seconds -| elasticsearch_indices_search_fetch_total | counter | 1 | Total number of fetches -| elasticsearch_indices_search_query_time_seconds | counter | 1 | Total search query time in seconds -| elasticsearch_indices_search_query_total | counter | 1 | Total number of queries -| elasticsearch_indices_segments_count | gauge | 1 | Count of index segments on this node -| elasticsearch_indices_segments_memory_bytes | gauge | 1 | Current memory size of segments in bytes -| elasticsearch_indices_settings_stats_read_only_indices | gauge | 1 | Count of indices that have read_only_allow_delete=true -| elasticsearch_indices_settings_total_fields | gauge | | Index setting value for index.mapping.total_fields.limit (total allowable mapped fields in a index) -| elasticsearch_indices_shards_docs | gauge | 3 | Count of documents on this shard -| elasticsearch_indices_shards_docs_deleted | gauge | 3 | Count of deleted documents on each shard -| elasticsearch_indices_store_size_bytes | gauge | 1 | Current size of stored index data in bytes -| elasticsearch_indices_store_size_bytes_primary | gauge | | Current size of stored index data in bytes with only primary shards on all nodes -| elasticsearch_indices_store_size_bytes_total | gauge | | Current size of stored index data in bytes with all shards on all nodes -| elasticsearch_indices_store_throttle_time_seconds_total | counter | 1 | Throttle time for index store in seconds -| elasticsearch_indices_translog_operations | counter | 1 | Total translog operations -| elasticsearch_indices_translog_size_in_bytes | counter | 1 | Total translog size in bytes -| elasticsearch_indices_warmer_time_seconds_total | counter | 1 | Total warmer time in seconds -| elasticsearch_indices_warmer_total | counter | 1 | Total warmer count -| elasticsearch_jvm_gc_collection_seconds_count | counter | 2 | Count of JVM GC runs -| elasticsearch_jvm_gc_collection_seconds_sum | counter | 2 | GC run time in seconds -| elasticsearch_jvm_memory_committed_bytes | gauge | 2 | JVM memory currently committed by area -| elasticsearch_jvm_memory_max_bytes | gauge | 1 | JVM memory max -| elasticsearch_jvm_memory_used_bytes | gauge | 2 | JVM memory currently used by area -| elasticsearch_jvm_memory_pool_used_bytes | gauge | 3 | JVM memory currently used by pool -| elasticsearch_jvm_memory_pool_max_bytes | counter | 3 | JVM memory max by pool -| elasticsearch_jvm_memory_pool_peak_used_bytes | counter | 3 | JVM memory peak used by pool -| elasticsearch_jvm_memory_pool_peak_max_bytes | counter | 3 | JVM memory peak max by pool -| elasticsearch_os_cpu_percent | gauge | 1 | Percent CPU used by the OS -| elasticsearch_os_load1 | gauge | 1 | Shortterm load average -| elasticsearch_os_load5 | gauge | 1 | Midterm load average -| elasticsearch_os_load15 | gauge | 1 | Longterm load average -| elasticsearch_process_cpu_percent | gauge | 1 | Percent CPU used by process -| elasticsearch_process_cpu_seconds_total | counter | 1 | Process CPU time in seconds -| elasticsearch_process_mem_resident_size_bytes | gauge | 1 | Resident memory in use by process in bytes -| elasticsearch_process_mem_share_size_bytes | gauge | 1 | Shared memory in use by process in bytes -| elasticsearch_process_mem_virtual_size_bytes | gauge | 1 | Total virtual memory used in bytes -| elasticsearch_process_open_files_count | gauge | 1 | Open file descriptors -| elasticsearch_snapshot_stats_number_of_snapshots | gauge | 1 | Total number of snapshots -| elasticsearch_snapshot_stats_oldest_snapshot_timestamp | gauge | 1 | Oldest snapshot timestamp -| elasticsearch_snapshot_stats_snapshot_start_time_timestamp | gauge | 1 | Last snapshot start timestamp -| elasticsearch_snapshot_stats_latest_snapshot_timestamp_seconds | gauge | 1 | Timestamp of the latest SUCCESS or PARTIAL snapshot -| elasticsearch_snapshot_stats_snapshot_end_time_timestamp | gauge | 1 | Last snapshot end timestamp -| elasticsearch_snapshot_stats_snapshot_number_of_failures | gauge | 1 | Last snapshot number of failures -| elasticsearch_snapshot_stats_snapshot_number_of_indices | gauge | 1 | Last snapshot number of indices -| elasticsearch_snapshot_stats_snapshot_failed_shards | gauge | 1 | Last snapshot failed shards -| elasticsearch_snapshot_stats_snapshot_successful_shards | gauge | 1 | Last snapshot successful shards -| elasticsearch_snapshot_stats_snapshot_total_shards | gauge | 1 | Last snapshot total shard -| elasticsearch_thread_pool_active_count | gauge | 14 | Thread Pool threads active -| elasticsearch_thread_pool_completed_count | counter | 14 | Thread Pool operations completed -| elasticsearch_thread_pool_largest_count | gauge | 14 | Thread Pool largest threads count -| elasticsearch_thread_pool_queue_count | gauge | 14 | Thread Pool operations queued -| elasticsearch_thread_pool_rejected_count | counter | 14 | Thread Pool operations rejected -| elasticsearch_thread_pool_threads_count | gauge | 14 | Thread Pool current threads count -| elasticsearch_transport_rx_packets_total | counter | 1 | Count of packets received -| elasticsearch_transport_rx_size_bytes_total | counter | 1 | Total number of bytes received -| elasticsearch_transport_tx_packets_total | counter | 1 | Count of packets sent -| elasticsearch_transport_tx_size_bytes_total | counter | 1 | Total number of bytes sent -| elasticsearch_clusterinfo_last_retrieval_success_ts | gauge | 1 | Timestamp of the last successful cluster info retrieval -| elasticsearch_clusterinfo_up | gauge | 1 | Up metric for the cluster info collector -| elasticsearch_clusterinfo_version_info | gauge | 6 | Constant metric with ES version information as labels -| elasticsearch_slm_stats_up | gauge | 0 | Up metric for SLM collector -| elasticsearch_slm_stats_total_scrapes | counter | 0 | Number of scrapes for SLM collector -| elasticsearch_slm_stats_json_parse_failures | counter | 0 | JSON parse failures for SLM collector -| elasticsearch_slm_stats_retention_runs_total | counter | 0 | Total retention runs -| elasticsearch_slm_stats_retention_failed_total | counter | 0 | Total failed retention runs -| elasticsearch_slm_stats_retention_timed_out_total | counter | 0 | Total retention run timeouts -| elasticsearch_slm_stats_retention_deletion_time_seconds | gauge | 0 | Retention run deletion time -| elasticsearch_slm_stats_total_snapshots_taken_total | counter | 0 | Total snapshots taken -| elasticsearch_slm_stats_total_snapshots_failed_total | counter | 0 | Total snapshots failed -| elasticsearch_slm_stats_total_snapshots_deleted_total | counter | 0 | Total snapshots deleted -| elasticsearch_slm_stats_total_snapshots_failed_total | counter | 0 | Total snapshots failed -| elasticsearch_slm_stats_snapshots_taken_total | counter | 1 | Snapshots taken by policy -| elasticsearch_slm_stats_snapshots_failed_total | counter | 1 | Snapshots failed by policy -| elasticsearch_slm_stats_snapshots_deleted_total | counter | 1 | Snapshots deleted by policy -| elasticsearch_slm_stats_snapshot_deletion_failures_total | counter | 1 | Snapshot deletion failures by policy -| elasticsearch_slm_stats_operation_mode | gauge | 1 | SLM operation mode (Running, stopping, stopped) - +| Name | Type | Cardinality | Help | +|----------------------------------------------------------------------|------------|-------------|-----------------------------------------------------------------------------------------------------| +| elasticsearch_breakers_estimated_size_bytes | gauge | 4 | Estimated size in bytes of breaker | +| elasticsearch_breakers_limit_size_bytes | gauge | 4 | Limit size in bytes for breaker | +| elasticsearch_breakers_tripped | counter | 4 | tripped for breaker | +| elasticsearch_cluster_health_active_primary_shards | gauge | 1 | The number of primary shards in your cluster. This is an aggregate total across all indices. | +| elasticsearch_cluster_health_active_shards | gauge | 1 | Aggregate total of all shards across all indices, which includes replica shards. | +| elasticsearch_cluster_health_delayed_unassigned_shards | gauge | 1 | Shards delayed to reduce reallocation overhead | +| elasticsearch_cluster_health_initializing_shards | gauge | 1 | Count of shards that are being freshly created. | +| elasticsearch_cluster_health_number_of_data_nodes | gauge | 1 | Number of data nodes in the cluster. | +| elasticsearch_cluster_health_number_of_in_flight_fetch | gauge | 1 | The number of ongoing shard info requests. | +| elasticsearch_cluster_health_number_of_nodes | gauge | 1 | Number of nodes in the cluster. | +| elasticsearch_cluster_health_number_of_pending_tasks | gauge | 1 | Cluster level changes which have not yet been executed | +| elasticsearch_cluster_health_task_max_waiting_in_queue_millis | gauge | 1 | Max time in millis that a task is waiting in queue. | +| elasticsearch_cluster_health_relocating_shards | gauge | 1 | The number of shards that are currently moving from one node to another node. | +| elasticsearch_cluster_health_status | gauge | 3 | Whether all primary and replica shards are allocated. | +| elasticsearch_cluster_health_timed_out | gauge | 1 | Number of cluster health checks timed out | +| elasticsearch_cluster_health_unassigned_shards | gauge | 1 | The number of shards that exist in the cluster state, but cannot be found in the cluster itself. | +| elasticsearch_clustersettings_stats_max_shards_per_node | gauge | 0 | Current maximum number of shards per node setting. | +| elasticsearch_clustersettings_allocation_threshold_enabled | gauge | 0 | Is disk allocation decider enabled. | +| elasticsearch_clustersettings_allocation_watermark_flood_stage_bytes | gauge | 0 | Flood stage watermark as in bytes. | +| elasticsearch_clustersettings_allocation_watermark_high_bytes | gauge | 0 | High watermark for disk usage in bytes. | +| elasticsearch_clustersettings_allocation_watermark_low_bytes | gauge | 0 | Low watermark for disk usage in bytes. | +| elasticsearch_clustersettings_allocation_watermark_flood_stage_ratio | gauge | 0 | Flood stage watermark as a ratio. | +| elasticsearch_clustersettings_allocation_watermark_high_ratio | gauge | 0 | High watermark for disk usage as a ratio. | +| elasticsearch_clustersettings_allocation_watermark_low_ratio | gauge | 0 | Low watermark for disk usage as a ratio. | +| elasticsearch_filesystem_data_available_bytes | gauge | 1 | Available space on block device in bytes | +| elasticsearch_filesystem_data_free_bytes | gauge | 1 | Free space on block device in bytes | +| elasticsearch_filesystem_data_size_bytes | gauge | 1 | Size of block device in bytes | +| elasticsearch_filesystem_io_stats_device_operations_count | gauge | 1 | Count of disk operations | +| elasticsearch_filesystem_io_stats_device_read_operations_count | gauge | 1 | Count of disk read operations | +| elasticsearch_filesystem_io_stats_device_write_operations_count | gauge | 1 | Count of disk write operations | +| elasticsearch_filesystem_io_stats_device_read_size_kilobytes_sum | gauge | 1 | Total kilobytes read from disk | +| elasticsearch_filesystem_io_stats_device_write_size_kilobytes_sum | gauge | 1 | Total kilobytes written to disk | +| elasticsearch_indices_active_queries | gauge | 1 | The number of currently active queries | +| elasticsearch_indices_docs | gauge | 1 | Count of documents on this node | +| elasticsearch_indices_docs_deleted | gauge | 1 | Count of deleted documents on this node | +| elasticsearch_indices_deleted_docs_primary | gauge | 1 | Count of deleted documents with only primary shards | +| elasticsearch_indices_docs_primary | gauge | 1 | Count of documents with only primary shards on all nodes | +| elasticsearch_indices_docs_total | gauge | | Count of documents with shards on all nodes | +| elasticsearch_indices_fielddata_evictions | counter | 1 | Evictions from field data | +| elasticsearch_indices_fielddata_memory_size_bytes | gauge | 1 | Field data cache memory usage in bytes | +| elasticsearch_indices_filter_cache_evictions | counter | 1 | Evictions from filter cache | +| elasticsearch_indices_filter_cache_memory_size_bytes | gauge | 1 | Filter cache memory usage in bytes | +| elasticsearch_indices_flush_time_seconds | counter | 1 | Cumulative flush time in seconds | +| elasticsearch_indices_flush_total | counter | 1 | Total flushes | +| elasticsearch_indices_get_exists_time_seconds | counter | 1 | Total time get exists in seconds | +| elasticsearch_indices_get_exists_total | counter | 1 | Total get exists operations | +| elasticsearch_indices_get_missing_time_seconds | counter | 1 | Total time of get missing in seconds | +| elasticsearch_indices_get_missing_total | counter | 1 | Total get missing | +| elasticsearch_indices_get_time_seconds | counter | 1 | Total get time in seconds | +| elasticsearch_indices_get_total | counter | 1 | Total get | +| elasticsearch_indices_indexing_delete_time_seconds_total | counter | 1 | Total time indexing delete in seconds | +| elasticsearch_indices_indexing_delete_total | counter | 1 | Total indexing deletes | +| elasticsearch_indices_index_current | gauge | 1 | The number of documents currently being indexed to an index | +| elasticsearch_indices_indexing_index_time_seconds_total | counter | 1 | Cumulative index time in seconds | +| elasticsearch_indices_indexing_index_total | counter | 1 | Total index calls | +| elasticsearch_indices_mappings_stats_fields | gauge | 1 | Count of fields currently mapped by index | +| elasticsearch_indices_mappings_stats_json_parse_failures_total | counter | 0 | Number of errors while parsing JSON | +| elasticsearch_indices_mappings_stats_scrapes_total | counter | 0 | Current total Elasticsearch Indices Mappings scrapes | +| elasticsearch_indices_mappings_stats_up | gauge | 0 | Was the last scrape of the Elasticsearch Indices Mappings endpoint successful | +| elasticsearch_indices_merges_docs_total | counter | 1 | Cumulative docs merged | +| elasticsearch_indices_merges_total | counter | 1 | Total merges | +| elasticsearch_indices_merges_total_size_bytes_total | counter | 1 | Total merge size in bytes | +| elasticsearch_indices_merges_total_time_seconds_total | counter | 1 | Total time spent merging in seconds | +| elasticsearch_indices_query_cache_cache_total | counter | 1 | Count of query cache | +| elasticsearch_indices_query_cache_cache_size | gauge | 1 | Size of query cache | +| elasticsearch_indices_query_cache_count | counter | 2 | Count of query cache hit/miss | +| elasticsearch_indices_query_cache_evictions | counter | 1 | Evictions from query cache | +| elasticsearch_indices_query_cache_memory_size_bytes | gauge | 1 | Query cache memory usage in bytes | +| elasticsearch_indices_query_cache_total | counter | 1 | Size of query cache total | +| elasticsearch_indices_refresh_time_seconds_total | counter | 1 | Total time spent refreshing in seconds | +| elasticsearch_indices_refresh_total | counter | 1 | Total refreshes | +| elasticsearch_indices_request_cache_count | counter | 2 | Count of request cache hit/miss | +| elasticsearch_indices_request_cache_evictions | counter | 1 | Evictions from request cache | +| elasticsearch_indices_request_cache_memory_size_bytes | gauge | 1 | Request cache memory usage in bytes | +| elasticsearch_indices_search_fetch_time_seconds | counter | 1 | Total search fetch time in seconds | +| elasticsearch_indices_search_fetch_total | counter | 1 | Total number of fetches | +| elasticsearch_indices_search_query_time_seconds | counter | 1 | Total search query time in seconds | +| elasticsearch_indices_search_query_total | counter | 1 | Total number of queries | +| elasticsearch_indices_segments_count | gauge | 1 | Count of index segments on this node | +| elasticsearch_indices_segments_memory_bytes | gauge | 1 | Current memory size of segments in bytes | +| elasticsearch_indices_settings_stats_read_only_indices | gauge | 1 | Count of indices that have read_only_allow_delete=true | +| elasticsearch_indices_settings_total_fields | gauge | | Index setting value for index.mapping.total_fields.limit (total allowable mapped fields in a index) | +| elasticsearch_indices_settings_replicas | gauge | | Index setting value for index.replicas | +| elasticsearch_indices_shards_docs | gauge | 3 | Count of documents on this shard | +| elasticsearch_indices_shards_docs_deleted | gauge | 3 | Count of deleted documents on each shard | +| elasticsearch_indices_store_size_bytes | gauge | 1 | Current size of stored index data in bytes | +| elasticsearch_indices_store_size_bytes_primary | gauge | | Current size of stored index data in bytes with only primary shards on all nodes | +| elasticsearch_indices_store_size_bytes_total | gauge | | Current size of stored index data in bytes with all shards on all nodes | +| elasticsearch_indices_store_throttle_time_seconds_total | counter | 1 | Throttle time for index store in seconds | +| elasticsearch_indices_translog_operations | counter | 1 | Total translog operations | +| elasticsearch_indices_translog_size_in_bytes | counter | 1 | Total translog size in bytes | +| elasticsearch_indices_warmer_time_seconds_total | counter | 1 | Total warmer time in seconds | +| elasticsearch_indices_warmer_total | counter | 1 | Total warmer count | +| elasticsearch_jvm_gc_collection_seconds_count | counter | 2 | Count of JVM GC runs | +| elasticsearch_jvm_gc_collection_seconds_sum | counter | 2 | GC run time in seconds | +| elasticsearch_jvm_memory_committed_bytes | gauge | 2 | JVM memory currently committed by area | +| elasticsearch_jvm_memory_max_bytes | gauge | 1 | JVM memory max | +| elasticsearch_jvm_memory_used_bytes | gauge | 2 | JVM memory currently used by area | +| elasticsearch_jvm_memory_pool_used_bytes | gauge | 3 | JVM memory currently used by pool | +| elasticsearch_jvm_memory_pool_max_bytes | counter | 3 | JVM memory max by pool | +| elasticsearch_jvm_memory_pool_peak_used_bytes | counter | 3 | JVM memory peak used by pool | +| elasticsearch_jvm_memory_pool_peak_max_bytes | counter | 3 | JVM memory peak max by pool | +| elasticsearch_os_cpu_percent | gauge | 1 | Percent CPU used by the OS | +| elasticsearch_os_load1 | gauge | 1 | Shortterm load average | +| elasticsearch_os_load5 | gauge | 1 | Midterm load average | +| elasticsearch_os_load15 | gauge | 1 | Longterm load average | +| elasticsearch_process_cpu_percent | gauge | 1 | Percent CPU used by process | +| elasticsearch_process_cpu_seconds_total | counter | 1 | Process CPU time in seconds | +| elasticsearch_process_mem_resident_size_bytes | gauge | 1 | Resident memory in use by process in bytes | +| elasticsearch_process_mem_share_size_bytes | gauge | 1 | Shared memory in use by process in bytes | +| elasticsearch_process_mem_virtual_size_bytes | gauge | 1 | Total virtual memory used in bytes | +| elasticsearch_process_open_files_count | gauge | 1 | Open file descriptors | +| elasticsearch_snapshot_stats_number_of_snapshots | gauge | 1 | Total number of snapshots | +| elasticsearch_snapshot_stats_oldest_snapshot_timestamp | gauge | 1 | Oldest snapshot timestamp | +| elasticsearch_snapshot_stats_snapshot_start_time_timestamp | gauge | 1 | Last snapshot start timestamp | +| elasticsearch_snapshot_stats_latest_snapshot_timestamp_seconds | gauge | 1 | Timestamp of the latest SUCCESS or PARTIAL snapshot | +| elasticsearch_snapshot_stats_snapshot_end_time_timestamp | gauge | 1 | Last snapshot end timestamp | +| elasticsearch_snapshot_stats_snapshot_number_of_failures | gauge | 1 | Last snapshot number of failures | +| elasticsearch_snapshot_stats_snapshot_number_of_indices | gauge | 1 | Last snapshot number of indices | +| elasticsearch_snapshot_stats_snapshot_failed_shards | gauge | 1 | Last snapshot failed shards | +| elasticsearch_snapshot_stats_snapshot_successful_shards | gauge | 1 | Last snapshot successful shards | +| elasticsearch_snapshot_stats_snapshot_total_shards | gauge | 1 | Last snapshot total shard | +| elasticsearch_thread_pool_active_count | gauge | 14 | Thread Pool threads active | +| elasticsearch_thread_pool_completed_count | counter | 14 | Thread Pool operations completed | +| elasticsearch_thread_pool_largest_count | gauge | 14 | Thread Pool largest threads count | +| elasticsearch_thread_pool_queue_count | gauge | 14 | Thread Pool operations queued | +| elasticsearch_thread_pool_rejected_count | counter | 14 | Thread Pool operations rejected | +| elasticsearch_thread_pool_threads_count | gauge | 14 | Thread Pool current threads count | +| elasticsearch_transport_rx_packets_total | counter | 1 | Count of packets received | +| elasticsearch_transport_rx_size_bytes_total | counter | 1 | Total number of bytes received | +| elasticsearch_transport_tx_packets_total | counter | 1 | Count of packets sent | +| elasticsearch_transport_tx_size_bytes_total | counter | 1 | Total number of bytes sent | +| elasticsearch_clusterinfo_last_retrieval_success_ts | gauge | 1 | Timestamp of the last successful cluster info retrieval | +| elasticsearch_clusterinfo_up | gauge | 1 | Up metric for the cluster info collector | +| elasticsearch_clusterinfo_version_info | gauge | 6 | Constant metric with ES version information as labels | +| elasticsearch_slm_stats_up | gauge | 0 | Up metric for SLM collector | +| elasticsearch_slm_stats_total_scrapes | counter | 0 | Number of scrapes for SLM collector | +| elasticsearch_slm_stats_json_parse_failures | counter | 0 | JSON parse failures for SLM collector | +| elasticsearch_slm_stats_retention_runs_total | counter | 0 | Total retention runs | +| elasticsearch_slm_stats_retention_failed_total | counter | 0 | Total failed retention runs | +| elasticsearch_slm_stats_retention_timed_out_total | counter | 0 | Total retention run timeouts | +| elasticsearch_slm_stats_retention_deletion_time_seconds | gauge | 0 | Retention run deletion time | +| elasticsearch_slm_stats_total_snapshots_taken_total | counter | 0 | Total snapshots taken | +| elasticsearch_slm_stats_total_snapshots_failed_total | counter | 0 | Total snapshots failed | +| elasticsearch_slm_stats_total_snapshots_deleted_total | counter | 0 | Total snapshots deleted | +| elasticsearch_slm_stats_total_snapshots_failed_total | counter | 0 | Total snapshots failed | +| elasticsearch_slm_stats_snapshots_taken_total | counter | 1 | Snapshots taken by policy | +| elasticsearch_slm_stats_snapshots_failed_total | counter | 1 | Snapshots failed by policy | +| elasticsearch_slm_stats_snapshots_deleted_total | counter | 1 | Snapshots deleted by policy | +| elasticsearch_slm_stats_snapshot_deletion_failures_total | counter | 1 | Snapshot deletion failures by policy | +| elasticsearch_slm_stats_operation_mode | gauge | 1 | SLM operation mode (Running, stopping, stopped) | +| elasticsearch_data_stream_stats_up | gauge | 0 | Up metric for Data Stream collection | +| elasticsearch_data_stream_stats_total_scrapes | counter | 0 | Total scrapes for Data Stream stats | +| elasticsearch_data_stream_stats_json_parse_failures | counter | 0 | Number of parsing failures for Data Stream stats | +| elasticsearch_data_stream_backing_indices_total | gauge | 1 | Number of backing indices for Data Stream | +| elasticsearch_data_stream_store_size_bytes | gauge | 1 | Current size of data stream backing indices in bytes | ### Alerts & Recording Rules We provide examples for [Prometheus](http://prometheus.io) [alerts and recording rules](examples/prometheus/elasticsearch.rules) as well as an [Grafana](http://www.grafana.org) [Dashboard](examples/grafana/dashboard.json) and a [Kubernetes](http://kubernetes.io) [Deployment](examples/kubernetes/deployment.yml). -The example dashboard needs the [node_exporter](https://github.com/prometheus/node_exporter) installed. In order to select the nodes that belong to the ElasticSearch cluster, we rely on a label `cluster`. +The example dashboard needs the [node_exporter](https://github.com/prometheus/node_exporter) installed. In order to select the nodes that belong to the Elasticsearch cluster, we rely on a label `cluster`. Depending on your setup, it can derived from the platform metadata: For example on [GCE](https://cloud.google.com) @@ -273,7 +296,7 @@ who transferred this repository to us in January 2017. Maintainers of this repository: -* Christoph Oelmüller @zwopir +- Christoph Oelmüller @zwopir Please refer to the Git commit log for a complete list of contributors. diff --git a/VERSION b/VERSION index f0bb29e7..dc1e644a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.3.0 +1.6.0 diff --git a/collector/cluster_health.go b/collector/cluster_health.go index 3b991818..0ea351d3 100644 --- a/collector/cluster_health.go +++ b/collector/cluster_health.go @@ -16,7 +16,7 @@ package collector import ( "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "net/url" "path" @@ -68,11 +68,11 @@ func NewClusterHealth(logger log.Logger, client *http.Client, url *url.URL) *Clu up: prometheus.NewGauge(prometheus.GaugeOpts{ Name: prometheus.BuildFQName(namespace, subsystem, "up"), - Help: "Was the last scrape of the ElasticSearch cluster health endpoint successful.", + Help: "Was the last scrape of the Elasticsearch cluster health endpoint successful.", }), totalScrapes: prometheus.NewCounter(prometheus.CounterOpts{ Name: prometheus.BuildFQName(namespace, subsystem, "total_scrapes"), - Help: "Current total ElasticSearch cluster health scrapes.", + Help: "Current total Elasticsearch cluster health scrapes.", }), jsonParseFailures: prometheus.NewCounter(prometheus.CounterOpts{ Name: prometheus.BuildFQName(namespace, subsystem, "json_parse_failures"), @@ -245,7 +245,7 @@ func (c *ClusterHealth) fetchAndDecodeClusterHealth() (clusterHealthResponse, er defer func() { err = res.Body.Close() if err != nil { - _ = level.Warn(c.logger).Log( + level.Warn(c.logger).Log( "msg", "failed to close http.Client", "err", err, ) @@ -256,7 +256,7 @@ func (c *ClusterHealth) fetchAndDecodeClusterHealth() (clusterHealthResponse, er return chr, fmt.Errorf("HTTP Request failed with code %d", res.StatusCode) } - bts, err := ioutil.ReadAll(res.Body) + bts, err := io.ReadAll(res.Body) if err != nil { c.jsonParseFailures.Inc() return chr, err @@ -283,7 +283,7 @@ func (c *ClusterHealth) Collect(ch chan<- prometheus.Metric) { clusterHealthResp, err := c.fetchAndDecodeClusterHealth() if err != nil { c.up.Set(0) - _ = level.Warn(c.logger).Log( + level.Warn(c.logger).Log( "msg", "failed to fetch and decode cluster health", "err", err, ) diff --git a/collector/cluster_info.go b/collector/cluster_info.go index 3649a214..d42ca57c 100644 --- a/collector/cluster_info.go +++ b/collector/cluster_info.go @@ -16,11 +16,11 @@ package collector import ( "context" "encoding/json" - "io/ioutil" + "io" "net/http" "net/url" - "github.com/blang/semver" + "github.com/blang/semver/v4" "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" ) @@ -83,7 +83,7 @@ func (c *ClusterInfoCollector) Update(ctx context.Context, ch chan<- prometheus. return err } defer resp.Body.Close() - b, err := ioutil.ReadAll(resp.Body) + b, err := io.ReadAll(resp.Body) if err != nil { return err } diff --git a/collector/cluster_settings.go b/collector/cluster_settings.go index 034a5fc5..4fbe9be8 100644 --- a/collector/cluster_settings.go +++ b/collector/cluster_settings.go @@ -14,157 +14,187 @@ package collector import ( + "context" "encoding/json" - "fmt" - "io/ioutil" + "io" "net/http" "net/url" - "path" "strconv" + "strings" "github.com/go-kit/log" - "github.com/go-kit/log/level" "github.com/imdario/mergo" "github.com/prometheus/client_golang/prometheus" ) -// ClusterSettings information struct -type ClusterSettings struct { - logger log.Logger - client *http.Client - url *url.URL +func init() { + registerCollector("clustersettings", defaultDisabled, NewClusterSettings) +} - up prometheus.Gauge - shardAllocationEnabled prometheus.Gauge - maxShardsPerNode prometheus.Gauge - totalScrapes, jsonParseFailures prometheus.Counter +type ClusterSettingsCollector struct { + logger log.Logger + u *url.URL + hc *http.Client } -// NewClusterSettings defines Cluster Settings Prometheus metrics -func NewClusterSettings(logger log.Logger, client *http.Client, url *url.URL) *ClusterSettings { - return &ClusterSettings{ +func NewClusterSettings(logger log.Logger, u *url.URL, hc *http.Client) (Collector, error) { + return &ClusterSettingsCollector{ logger: logger, - client: client, - url: url, - - up: prometheus.NewGauge(prometheus.GaugeOpts{ - Name: prometheus.BuildFQName(namespace, "clustersettings_stats", "up"), - Help: "Was the last scrape of the ElasticSearch cluster settings endpoint successful.", - }), - totalScrapes: prometheus.NewCounter(prometheus.CounterOpts{ - Name: prometheus.BuildFQName(namespace, "clustersettings_stats", "total_scrapes"), - Help: "Current total ElasticSearch cluster settings scrapes.", - }), - shardAllocationEnabled: prometheus.NewGauge(prometheus.GaugeOpts{ - Name: prometheus.BuildFQName(namespace, "clustersettings_stats", "shard_allocation_enabled"), - Help: "Current mode of cluster wide shard routing allocation settings.", - }), - maxShardsPerNode: prometheus.NewGauge(prometheus.GaugeOpts{ - Name: prometheus.BuildFQName(namespace, "clustersettings_stats", "max_shards_per_node"), - Help: "Current maximum number of shards per node setting.", - }), - jsonParseFailures: prometheus.NewCounter(prometheus.CounterOpts{ - Name: prometheus.BuildFQName(namespace, "clustersettings_stats", "json_parse_failures"), - Help: "Number of errors while parsing JSON.", - }), - } + u: u, + hc: hc, + }, nil } -// Describe add Snapshots metrics descriptions -func (cs *ClusterSettings) Describe(ch chan<- *prometheus.Desc) { - ch <- cs.up.Desc() - ch <- cs.totalScrapes.Desc() - ch <- cs.shardAllocationEnabled.Desc() - ch <- cs.maxShardsPerNode.Desc() - ch <- cs.jsonParseFailures.Desc() +var clusterSettingsDesc = map[string]*prometheus.Desc{ + "shardAllocationEnabled": prometheus.NewDesc( + prometheus.BuildFQName(namespace, "clustersettings_stats", "shard_allocation_enabled"), + "Current mode of cluster wide shard routing allocation settings.", + nil, nil, + ), + + "maxShardsPerNode": prometheus.NewDesc( + prometheus.BuildFQName(namespace, "clustersettings_stats", "max_shards_per_node"), + "Current maximum number of shards per node setting.", + nil, nil, + ), + + "thresholdEnabled": prometheus.NewDesc( + prometheus.BuildFQName(namespace, "clustersettings_allocation", "threshold_enabled"), + "Is disk allocation decider enabled.", + nil, nil, + ), + + "floodStageRatio": prometheus.NewDesc( + prometheus.BuildFQName(namespace, "clustersettings_allocation_watermark", "flood_stage_ratio"), + "Flood stage watermark as a ratio.", + nil, nil, + ), + + "highRatio": prometheus.NewDesc( + prometheus.BuildFQName(namespace, "clustersettings_allocation_watermark", "high_ratio"), + "High watermark for disk usage as a ratio.", + nil, nil, + ), + + "lowRatio": prometheus.NewDesc( + prometheus.BuildFQName(namespace, "clustersettings_allocation_watermark", "low_ratio"), + "Low watermark for disk usage as a ratio.", + nil, nil, + ), + + "floodStageBytes": prometheus.NewDesc( + prometheus.BuildFQName(namespace, "clustersettings_allocation_watermark", "flood_stage_bytes"), + "Flood stage watermark as in bytes.", + nil, nil, + ), + + "highBytes": prometheus.NewDesc( + prometheus.BuildFQName(namespace, "clustersettings_allocation_watermark", "high_bytes"), + "High watermark for disk usage in bytes.", + nil, nil, + ), + + "lowBytes": prometheus.NewDesc( + prometheus.BuildFQName(namespace, "clustersettings_allocation_watermark", "low_bytes"), + "Low watermark for disk usage in bytes.", + nil, nil, + ), } -func (cs *ClusterSettings) getAndParseURL(u *url.URL, data interface{}) error { - res, err := cs.client.Get(u.String()) - if err != nil { - return fmt.Errorf("failed to get from %s://%s:%s%s: %s", - u.Scheme, u.Hostname(), u.Port(), u.Path, err) - } +// clusterSettingsResponse is a representation of a Elasticsearch Cluster Settings +type clusterSettingsResponse struct { + Defaults clusterSettingsSection `json:"defaults"` + Persistent clusterSettingsSection `json:"persistent"` + Transient clusterSettingsSection `json:"transient"` +} - defer func() { - err = res.Body.Close() - if err != nil { - _ = level.Warn(cs.logger).Log( - "msg", "failed to close http.Client", - "err", err, - ) - } - }() +// clusterSettingsSection is a representation of a Elasticsearch Cluster Settings +type clusterSettingsSection struct { + Cluster clusterSettingsCluster `json:"cluster"` +} - if res.StatusCode != http.StatusOK { - return fmt.Errorf("HTTP Request failed with code %d", res.StatusCode) - } +// clusterSettingsCluster is a representation of a Elasticsearch clusterSettingsCluster Settings +type clusterSettingsCluster struct { + Routing clusterSettingsRouting `json:"routing"` + // This can be either a JSON object (which does not contain the value we are interested in) or a string + MaxShardsPerNode interface{} `json:"max_shards_per_node"` +} - bts, err := ioutil.ReadAll(res.Body) - if err != nil { - cs.jsonParseFailures.Inc() - return err - } +// clusterSettingsRouting is a representation of a Elasticsearch Cluster shard routing configuration +type clusterSettingsRouting struct { + Allocation clusterSettingsAllocation `json:"allocation"` +} - if err := json.Unmarshal(bts, data); err != nil { - cs.jsonParseFailures.Inc() - return err - } +// clusterSettingsAllocation is a representation of a Elasticsearch Cluster shard routing allocation settings +type clusterSettingsAllocation struct { + Enabled string `json:"enable"` + Disk clusterSettingsDisk `json:"disk"` +} - return nil +// clusterSettingsDisk is a representation of a Elasticsearch Cluster shard routing disk allocation settings +type clusterSettingsDisk struct { + ThresholdEnabled string `json:"threshold_enabled"` + Watermark clusterSettingsWatermark `json:"watermark"` } -func (cs *ClusterSettings) fetchAndDecodeClusterSettingsStats() (ClusterSettingsResponse, error) { +// clusterSettingsWatermark is representation of Elasticsearch Cluster shard routing disk allocation watermark settings +type clusterSettingsWatermark struct { + FloodStage string `json:"flood_stage"` + High string `json:"high"` + Low string `json:"low"` +} - u := *cs.url - u.Path = path.Join(u.Path, "/_cluster/settings") +func (c *ClusterSettingsCollector) Update(ctx context.Context, ch chan<- prometheus.Metric) error { + u := c.u.ResolveReference(&url.URL{Path: "_cluster/settings"}) q := u.Query() q.Set("include_defaults", "true") u.RawQuery = q.Encode() - u.RawPath = q.Encode() - var csfr ClusterSettingsFullResponse - var csr ClusterSettingsResponse - err := cs.getAndParseURL(&u, &csfr) + + req, err := http.NewRequestWithContext(ctx, "GET", u.String(), nil) if err != nil { - return csr, err + return err } - err = mergo.Merge(&csr, csfr.Defaults, mergo.WithOverride) + + resp, err := c.hc.Do(req) if err != nil { - return csr, err + return err } - err = mergo.Merge(&csr, csfr.Persistent, mergo.WithOverride) + defer resp.Body.Close() + b, err := io.ReadAll(resp.Body) if err != nil { - return csr, err + return err + } + var data clusterSettingsResponse + err = json.Unmarshal(b, &data) + if err != nil { + return err } - err = mergo.Merge(&csr, csfr.Transient, mergo.WithOverride) - - return csr, err -} - -// Collect gets cluster settings metric values -func (cs *ClusterSettings) Collect(ch chan<- prometheus.Metric) { - cs.totalScrapes.Inc() - defer func() { - ch <- cs.up - ch <- cs.totalScrapes - ch <- cs.jsonParseFailures - ch <- cs.shardAllocationEnabled - ch <- cs.maxShardsPerNode - }() + // Merge all settings into one struct + merged := data.Defaults - csr, err := cs.fetchAndDecodeClusterSettingsStats() + err = mergo.Merge(&merged, data.Persistent, mergo.WithOverride) if err != nil { - cs.shardAllocationEnabled.Set(0) - cs.up.Set(0) - _ = level.Warn(cs.logger).Log( - "msg", "failed to fetch and decode cluster settings stats", - "err", err, - ) - return + return err + } + err = mergo.Merge(&merged, data.Transient, mergo.WithOverride) + if err != nil { + return err } - cs.up.Set(1) + // Max shards per node + if maxShardsPerNodeString, ok := merged.Cluster.MaxShardsPerNode.(string); ok { + maxShardsPerNode, err := strconv.ParseInt(maxShardsPerNodeString, 10, 64) + if err == nil { + ch <- prometheus.MustNewConstMetric( + clusterSettingsDesc["maxShardsPerNode"], + prometheus.GaugeValue, + float64(maxShardsPerNode), + ) + } + } + + // Shard allocation enabled shardAllocationMap := map[string]int{ "all": 0, "primaries": 1, @@ -172,10 +202,112 @@ func (cs *ClusterSettings) Collect(ch chan<- prometheus.Metric) { "none": 3, } - cs.shardAllocationEnabled.Set(float64(shardAllocationMap[csr.Cluster.Routing.Allocation.Enabled])) + ch <- prometheus.MustNewConstMetric( + clusterSettingsDesc["shardAllocationEnabled"], + prometheus.GaugeValue, + float64(shardAllocationMap[merged.Cluster.Routing.Allocation.Enabled]), + ) + + // Threshold enabled + thresholdMap := map[string]int{ + "false": 0, + "true": 1, + } + + ch <- prometheus.MustNewConstMetric( + clusterSettingsDesc["thresholdEnabled"], + prometheus.GaugeValue, + float64(thresholdMap[merged.Cluster.Routing.Allocation.Disk.ThresholdEnabled]), + ) + + // Watermark bytes or ratio metrics + if strings.HasSuffix(merged.Cluster.Routing.Allocation.Disk.Watermark.High, "b") { + ch <- prometheus.MustNewConstMetric( + clusterSettingsDesc["floodStageBytes"], + prometheus.GaugeValue, + getValueInBytes(merged.Cluster.Routing.Allocation.Disk.Watermark.FloodStage), + ) + + ch <- prometheus.MustNewConstMetric( + clusterSettingsDesc["highBytes"], + prometheus.GaugeValue, + getValueInBytes(merged.Cluster.Routing.Allocation.Disk.Watermark.High), + ) + + ch <- prometheus.MustNewConstMetric( + clusterSettingsDesc["lowBytes"], + prometheus.GaugeValue, + getValueInBytes(merged.Cluster.Routing.Allocation.Disk.Watermark.Low), + ) + + return nil + } + + ch <- prometheus.MustNewConstMetric( + clusterSettingsDesc["floodStageRatio"], + prometheus.GaugeValue, + getValueAsRatio(merged.Cluster.Routing.Allocation.Disk.Watermark.FloodStage), + ) + + ch <- prometheus.MustNewConstMetric( + clusterSettingsDesc["highRatio"], + prometheus.GaugeValue, + getValueAsRatio(merged.Cluster.Routing.Allocation.Disk.Watermark.High), + ) + + ch <- prometheus.MustNewConstMetric( + clusterSettingsDesc["lowRatio"], + prometheus.GaugeValue, + getValueAsRatio(merged.Cluster.Routing.Allocation.Disk.Watermark.Low), + ) + + return nil +} + +func getValueInBytes(value string) float64 { + type UnitValue struct { + unit string + val float64 + } + + unitValues := []UnitValue{ + {"pb", 1024 * 1024 * 1024 * 1024 * 1024}, + {"tb", 1024 * 1024 * 1024 * 1024}, + {"gb", 1024 * 1024 * 1024}, + {"mb", 1024 * 1024}, + {"kb", 1024}, + {"b", 1}, + } + + for _, uv := range unitValues { + if strings.HasSuffix(value, uv.unit) { + numberStr := strings.TrimSuffix(value, uv.unit) - maxShardsPerNode, err := strconv.ParseInt(csr.Cluster.MaxShardsPerNode, 10, 64) - if err == nil { - cs.maxShardsPerNode.Set(float64(maxShardsPerNode)) + number, err := strconv.ParseFloat(numberStr, 64) + if err != nil { + return 0 + } + return number * uv.val + } } + + return 0 +} + +func getValueAsRatio(value string) float64 { + if strings.HasSuffix(value, "%") { + percentValue, err := strconv.Atoi(strings.TrimSpace(strings.TrimSuffix(value, "%"))) + if err != nil { + return 0 + } + + return float64(percentValue) / 100 + } + + ratio, err := strconv.ParseFloat(value, 64) + if err != nil { + return 0 + } + + return ratio } diff --git a/collector/cluster_settings_response.go b/collector/cluster_settings_response.go deleted file mode 100644 index 4b79899c..00000000 --- a/collector/cluster_settings_response.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2021 The Prometheus Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package collector - -// ClusterSettingsFullResponse is a representation of a Elasticsearch Cluster Settings -type ClusterSettingsFullResponse struct { - Defaults ClusterSettingsResponse `json:"defaults"` - Persistent ClusterSettingsResponse `json:"persistent"` - Transient ClusterSettingsResponse `json:"transient"` -} - -// ClusterSettingsResponse is a representation of a Elasticsearch Cluster Settings -type ClusterSettingsResponse struct { - Cluster Cluster `json:"cluster"` -} - -// Cluster is a representation of a Elasticsearch Cluster Settings -type Cluster struct { - Routing Routing `json:"routing"` - MaxShardsPerNode string `json:"max_shards_per_node"` -} - -// Routing is a representation of a Elasticsearch Cluster shard routing configuration -type Routing struct { - Allocation Allocation `json:"allocation"` -} - -// Allocation is a representation of a Elasticsearch Cluster shard routing allocation settings -type Allocation struct { - Enabled string `json:"enable"` -} diff --git a/collector/cluster_settings_test.go b/collector/cluster_settings_test.go index 6a39aa4a..e3691ef1 100644 --- a/collector/cluster_settings_test.go +++ b/collector/cluster_settings_test.go @@ -14,80 +14,161 @@ package collector import ( + "context" "io" "net/http" "net/http/httptest" "net/url" "os" + "strings" "testing" "github.com/go-kit/log" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/testutil" ) +type wrapCollector struct { + c Collector +} + +func (w wrapCollector) Describe(ch chan<- *prometheus.Desc) { +} + +func (w wrapCollector) Collect(ch chan<- prometheus.Metric) { + w.c.Update(context.Background(), ch) +} + func TestClusterSettingsStats(t *testing.T) { // Testcases created using: // docker run -d -p 9200:9200 elasticsearch:VERSION-alpine // curl http://localhost:9200/_cluster/settings/?include_defaults=true - files := []string{"../fixtures/settings-5.4.2.json", "../fixtures/settings-merge-5.4.2.json"} - for _, filename := range files { - f, _ := os.Open(filename) - defer f.Close() - for hn, handler := range map[string]http.Handler{ - "plain": http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - io.Copy(w, f) - }), - } { - ts := httptest.NewServer(handler) - defer ts.Close() - u, err := url.Parse(ts.URL) - if err != nil { - t.Fatalf("Failed to parse URL: %s", err) - } - c := NewClusterSettings(log.NewNopLogger(), http.DefaultClient, u) - nsr, err := c.fetchAndDecodeClusterSettingsStats() + tests := []struct { + name string + file string + want string + }{ + // MaxShardsPerNode is empty in older versions + { + name: "5.4.2", + file: "../fixtures/settings-5.4.2.json", + want: ` +# HELP elasticsearch_clustersettings_stats_shard_allocation_enabled Current mode of cluster wide shard routing allocation settings. +# TYPE elasticsearch_clustersettings_stats_shard_allocation_enabled gauge +elasticsearch_clustersettings_stats_shard_allocation_enabled 0 +# HELP elasticsearch_clustersettings_allocation_threshold_enabled Is disk allocation decider enabled. +# TYPE elasticsearch_clustersettings_allocation_threshold_enabled gauge +elasticsearch_clustersettings_allocation_threshold_enabled 1 +# HELP elasticsearch_clustersettings_allocation_watermark_flood_stage_ratio Flood stage watermark as a ratio. +# TYPE elasticsearch_clustersettings_allocation_watermark_flood_stage_ratio gauge +elasticsearch_clustersettings_allocation_watermark_flood_stage_ratio 0 +# HELP elasticsearch_clustersettings_allocation_watermark_high_ratio High watermark for disk usage as a ratio. +# TYPE elasticsearch_clustersettings_allocation_watermark_high_ratio gauge +elasticsearch_clustersettings_allocation_watermark_high_ratio 0.9 +# HELP elasticsearch_clustersettings_allocation_watermark_low_ratio Low watermark for disk usage as a ratio. +# TYPE elasticsearch_clustersettings_allocation_watermark_low_ratio gauge +elasticsearch_clustersettings_allocation_watermark_low_ratio 0.85 +`, + }, + + { + name: "5.4.2-merge", + file: "../fixtures/settings-merge-5.4.2.json", + want: ` +# HELP elasticsearch_clustersettings_stats_shard_allocation_enabled Current mode of cluster wide shard routing allocation settings. +# TYPE elasticsearch_clustersettings_stats_shard_allocation_enabled gauge +elasticsearch_clustersettings_stats_shard_allocation_enabled 0 +# HELP elasticsearch_clustersettings_allocation_threshold_enabled Is disk allocation decider enabled. +# TYPE elasticsearch_clustersettings_allocation_threshold_enabled gauge +elasticsearch_clustersettings_allocation_threshold_enabled 0 +# HELP elasticsearch_clustersettings_allocation_watermark_flood_stage_ratio Flood stage watermark as a ratio. +# TYPE elasticsearch_clustersettings_allocation_watermark_flood_stage_ratio gauge +elasticsearch_clustersettings_allocation_watermark_flood_stage_ratio 0 +# HELP elasticsearch_clustersettings_allocation_watermark_high_ratio High watermark for disk usage as a ratio. +# TYPE elasticsearch_clustersettings_allocation_watermark_high_ratio gauge +elasticsearch_clustersettings_allocation_watermark_high_ratio 0 +# HELP elasticsearch_clustersettings_allocation_watermark_low_ratio Low watermark for disk usage as a ratio. +# TYPE elasticsearch_clustersettings_allocation_watermark_low_ratio gauge +elasticsearch_clustersettings_allocation_watermark_low_ratio 0 +`, + }, + { + name: "7.3.0", + file: "../fixtures/settings-7.3.0.json", + want: ` +# HELP elasticsearch_clustersettings_stats_max_shards_per_node Current maximum number of shards per node setting. +# TYPE elasticsearch_clustersettings_stats_max_shards_per_node gauge +elasticsearch_clustersettings_stats_max_shards_per_node 1000 +# HELP elasticsearch_clustersettings_stats_shard_allocation_enabled Current mode of cluster wide shard routing allocation settings. +# TYPE elasticsearch_clustersettings_stats_shard_allocation_enabled gauge +elasticsearch_clustersettings_stats_shard_allocation_enabled 0 +# HELP elasticsearch_clustersettings_allocation_threshold_enabled Is disk allocation decider enabled. +# TYPE elasticsearch_clustersettings_allocation_threshold_enabled gauge +elasticsearch_clustersettings_allocation_threshold_enabled 0 +# HELP elasticsearch_clustersettings_allocation_watermark_flood_stage_ratio Flood stage watermark as a ratio. +# TYPE elasticsearch_clustersettings_allocation_watermark_flood_stage_ratio gauge +elasticsearch_clustersettings_allocation_watermark_flood_stage_ratio 0.95 +# HELP elasticsearch_clustersettings_allocation_watermark_high_ratio High watermark for disk usage as a ratio. +# TYPE elasticsearch_clustersettings_allocation_watermark_high_ratio gauge +elasticsearch_clustersettings_allocation_watermark_high_ratio 0.9 +# HELP elasticsearch_clustersettings_allocation_watermark_low_ratio Low watermark for disk usage as a ratio. +# TYPE elasticsearch_clustersettings_allocation_watermark_low_ratio gauge +elasticsearch_clustersettings_allocation_watermark_low_ratio 0.85 +`, + }, + { + name: "7.17.5-persistent-clustermaxshardspernode", + file: "../fixtures/settings-persistent-clustermaxshardspernode-7.17.5.json", + want: ` +# HELP elasticsearch_clustersettings_stats_max_shards_per_node Current maximum number of shards per node setting. +# TYPE elasticsearch_clustersettings_stats_max_shards_per_node gauge +elasticsearch_clustersettings_stats_max_shards_per_node 1000 +# HELP elasticsearch_clustersettings_stats_shard_allocation_enabled Current mode of cluster wide shard routing allocation settings. +# TYPE elasticsearch_clustersettings_stats_shard_allocation_enabled gauge +elasticsearch_clustersettings_stats_shard_allocation_enabled 0 +# HELP elasticsearch_clustersettings_allocation_threshold_enabled Is disk allocation decider enabled. +# TYPE elasticsearch_clustersettings_allocation_threshold_enabled gauge +elasticsearch_clustersettings_allocation_threshold_enabled 1 +# HELP elasticsearch_clustersettings_allocation_watermark_flood_stage_bytes Flood stage watermark as in bytes. +# TYPE elasticsearch_clustersettings_allocation_watermark_flood_stage_bytes gauge +elasticsearch_clustersettings_allocation_watermark_flood_stage_bytes 100 +# HELP elasticsearch_clustersettings_allocation_watermark_high_bytes High watermark for disk usage in bytes. +# TYPE elasticsearch_clustersettings_allocation_watermark_high_bytes gauge +elasticsearch_clustersettings_allocation_watermark_high_bytes 2.147483648e+11 +# HELP elasticsearch_clustersettings_allocation_watermark_low_bytes Low watermark for disk usage in bytes. +# TYPE elasticsearch_clustersettings_allocation_watermark_low_bytes gauge +elasticsearch_clustersettings_allocation_watermark_low_bytes 5.24288e+07 +`, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + f, err := os.Open(tt.file) if err != nil { - t.Fatalf("Failed to fetch or decode cluster settings stats: %s", err) - } - t.Logf("[%s/%s] Cluster Settings Stats Response: %+v", hn, filename, nsr) - if nsr.Cluster.Routing.Allocation.Enabled != "ALL" { - t.Errorf("Wrong setting for cluster routing allocation enabled") + t.Fatal(err) } - if nsr.Cluster.MaxShardsPerNode != "" { - t.Errorf("MaxShardsPerNode should be empty on older releases") - } - } - } -} + defer f.Close() -func TestClusterMaxShardsPerNode(t *testing.T) { - // Testcases created using: - // docker run -d -p 9200:9200 elasticsearch:VERSION-alpine - // curl http://localhost:9200/_cluster/settings/?include_defaults=true - files := []string{"../fixtures/settings-7.3.0.json"} - for _, filename := range files { - f, _ := os.Open(filename) - defer f.Close() - for hn, handler := range map[string]http.Handler{ - "plain": http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { io.Copy(w, f) - }), - } { - ts := httptest.NewServer(handler) + })) defer ts.Close() + u, err := url.Parse(ts.URL) if err != nil { - t.Fatalf("Failed to parse URL: %s", err) + t.Fatal(err) } - c := NewClusterSettings(log.NewNopLogger(), http.DefaultClient, u) - nsr, err := c.fetchAndDecodeClusterSettingsStats() + + c, err := NewClusterSettings(log.NewNopLogger(), u, http.DefaultClient) if err != nil { - t.Fatalf("Failed to fetch or decode cluster settings stats: %s", err) + t.Fatal(err) } - t.Logf("[%s/%s] Cluster Settings Stats Response: %+v", hn, filename, nsr) - if nsr.Cluster.MaxShardsPerNode != "1000" { - t.Errorf("Wrong value for MaxShardsPerNode") + + if err := testutil.CollectAndCompare(wrapCollector{c}, strings.NewReader(tt.want)); err != nil { + t.Fatal(err) } - } + }) } } diff --git a/collector/collector.go b/collector/collector.go index c08a9994..d8b56abb 100644 --- a/collector/collector.go +++ b/collector/collector.go @@ -23,18 +23,18 @@ import ( "sync" "time" + "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" - "gopkg.in/alecthomas/kingpin.v2" ) const ( // Namespace defines the common namespace to be used by all metrics. namespace = "elasticsearch" - defaultEnabled = true - // defaultDisabled = false + defaultEnabled = true + defaultDisabled = false ) type factoryFunc func(logger log.Logger, u *url.URL, hc *http.Client) (Collector, error) @@ -184,13 +184,13 @@ func execute(ctx context.Context, name string, c Collector, ch chan<- prometheus if err != nil { if IsNoDataError(err) { - _ = level.Debug(logger).Log("msg", "collector returned no data", "name", name, "duration_seconds", duration.Seconds(), "err", err) + level.Debug(logger).Log("msg", "collector returned no data", "name", name, "duration_seconds", duration.Seconds(), "err", err) } else { - _ = level.Error(logger).Log("msg", "collector failed", "name", name, "duration_seconds", duration.Seconds(), "err", err) + level.Error(logger).Log("msg", "collector failed", "name", name, "duration_seconds", duration.Seconds(), "err", err) } success = 0 } else { - _ = level.Debug(logger).Log("msg", "collector succeeded", "name", name, "duration_seconds", duration.Seconds()) + level.Debug(logger).Log("msg", "collector succeeded", "name", name, "duration_seconds", duration.Seconds()) success = 1 } ch <- prometheus.MustNewConstMetric(scrapeDurationDesc, prometheus.GaugeValue, duration.Seconds(), name) diff --git a/collector/data_stream.go b/collector/data_stream.go new file mode 100644 index 00000000..1edceb3a --- /dev/null +++ b/collector/data_stream.go @@ -0,0 +1,185 @@ +// Copyright 2022 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package collector + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "net/url" + "path" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/prometheus/client_golang/prometheus" +) + +type dataStreamMetric struct { + Type prometheus.ValueType + Desc *prometheus.Desc + Value func(dataStreamStats DataStreamStatsDataStream) float64 + Labels func(dataStreamStats DataStreamStatsDataStream) []string +} + +var ( + defaultDataStreamLabels = []string{"data_stream"} + defaultDataStreamLabelValues = func(dataStreamStats DataStreamStatsDataStream) []string { + return []string{dataStreamStats.DataStream} + } +) + +// DataStream Information Struct +type DataStream struct { + logger log.Logger + client *http.Client + url *url.URL + + up prometheus.Gauge + totalScrapes, jsonParseFailures prometheus.Counter + + dataStreamMetrics []*dataStreamMetric +} + +// NewDataStream defines DataStream Prometheus metrics +func NewDataStream(logger log.Logger, client *http.Client, url *url.URL) *DataStream { + return &DataStream{ + logger: logger, + client: client, + url: url, + + up: prometheus.NewGauge(prometheus.GaugeOpts{ + Name: prometheus.BuildFQName(namespace, "data_stream_stats", "up"), + Help: "Was the last scrape of the ElasticSearch Data Stream stats endpoint successful.", + }), + totalScrapes: prometheus.NewCounter(prometheus.CounterOpts{ + Name: prometheus.BuildFQName(namespace, "data_stream_stats", "total_scrapes"), + Help: "Current total ElasticSearch Data STream scrapes.", + }), + jsonParseFailures: prometheus.NewCounter(prometheus.CounterOpts{ + Name: prometheus.BuildFQName(namespace, "data_stream_stats", "json_parse_failures"), + Help: "Number of errors while parsing JSON.", + }), + dataStreamMetrics: []*dataStreamMetric{ + { + Type: prometheus.CounterValue, + Desc: prometheus.NewDesc( + prometheus.BuildFQName(namespace, "data_stream", "backing_indices_total"), + "Number of backing indices", + defaultDataStreamLabels, nil, + ), + Value: func(dataStreamStats DataStreamStatsDataStream) float64 { + return float64(dataStreamStats.BackingIndices) + }, + Labels: defaultDataStreamLabelValues, + }, + { + Type: prometheus.CounterValue, + Desc: prometheus.NewDesc( + prometheus.BuildFQName(namespace, "data_stream", "store_size_bytes"), + "Store size of data stream", + defaultDataStreamLabels, nil, + ), + Value: func(dataStreamStats DataStreamStatsDataStream) float64 { + return float64(dataStreamStats.StoreSizeBytes) + }, + Labels: defaultDataStreamLabelValues, + }, + }, + } +} + +// Describe adds DataStream metrics descriptions +func (ds *DataStream) Describe(ch chan<- *prometheus.Desc) { + for _, metric := range ds.dataStreamMetrics { + ch <- metric.Desc + } + + ch <- ds.up.Desc() + ch <- ds.totalScrapes.Desc() + ch <- ds.jsonParseFailures.Desc() +} + +func (ds *DataStream) fetchAndDecodeDataStreamStats() (DataStreamStatsResponse, error) { + var dsr DataStreamStatsResponse + + u := *ds.url + u.Path = path.Join(u.Path, "/_data_stream/*/_stats") + res, err := ds.client.Get(u.String()) + if err != nil { + return dsr, fmt.Errorf("failed to get data stream stats health from %s://%s:%s%s: %s", + u.Scheme, u.Hostname(), u.Port(), u.Path, err) + } + + defer func() { + err = res.Body.Close() + if err != nil { + level.Warn(ds.logger).Log( + "msg", "failed to close http.Client", + "err", err, + ) + } + }() + + if res.StatusCode != http.StatusOK { + return dsr, fmt.Errorf("HTTP Request failed with code %d", res.StatusCode) + } + + bts, err := io.ReadAll(res.Body) + if err != nil { + ds.jsonParseFailures.Inc() + return dsr, err + } + + if err := json.Unmarshal(bts, &dsr); err != nil { + ds.jsonParseFailures.Inc() + return dsr, err + } + + return dsr, nil +} + +// Collect gets DataStream metric values +func (ds *DataStream) Collect(ch chan<- prometheus.Metric) { + ds.totalScrapes.Inc() + defer func() { + ch <- ds.up + ch <- ds.totalScrapes + ch <- ds.jsonParseFailures + }() + + dataStreamStatsResp, err := ds.fetchAndDecodeDataStreamStats() + if err != nil { + ds.up.Set(0) + level.Warn(ds.logger).Log( + "msg", "failed to fetch and decode data stream stats", + "err", err, + ) + return + } + + ds.up.Set(1) + + for _, metric := range ds.dataStreamMetrics { + for _, dataStream := range dataStreamStatsResp.DataStreamStats { + fmt.Printf("Metric: %+v", dataStream) + ch <- prometheus.MustNewConstMetric( + metric.Desc, + metric.Type, + metric.Value(dataStream), + metric.Labels(dataStream)..., + ) + } + } +} diff --git a/collector/data_stream_response.go b/collector/data_stream_response.go new file mode 100644 index 00000000..41365a09 --- /dev/null +++ b/collector/data_stream_response.go @@ -0,0 +1,38 @@ +// Copyright 2022 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package collector + +// DataStreamStatsResponse is a representation of the Data Stream stats +type DataStreamStatsResponse struct { + Shards DataStreamStatsShards `json:"_shards"` + DataStreamCount int64 `json:"data_stream_count"` + BackingIndices int64 `json:"backing_indices"` + TotalStoreSizeBytes int64 `json:"total_store_size_bytes"` + DataStreamStats []DataStreamStatsDataStream `json:"data_streams"` +} + +// DataStreamStatsShards defines data stream stats shards information structure +type DataStreamStatsShards struct { + Total int64 `json:"total"` + Successful int64 `json:"successful"` + Failed int64 `json:"failed"` +} + +// DataStreamStatsDataStream defines the structure of per data stream stats +type DataStreamStatsDataStream struct { + DataStream string `json:"data_stream"` + BackingIndices int64 `json:"backing_indices"` + StoreSizeBytes int64 `json:"store_size_bytes"` + MaximumTimestamp int64 `json:"maximum_timestamp"` +} diff --git a/collector/data_stream_test.go b/collector/data_stream_test.go new file mode 100644 index 00000000..4a1279cb --- /dev/null +++ b/collector/data_stream_test.go @@ -0,0 +1,57 @@ +// Copyright 2022 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package collector + +import ( + "fmt" + "net/http" + "net/http/httptest" + "net/url" + "testing" + + "github.com/go-kit/log" +) + +func TestDataStream(t *testing.T) { + tcs := map[string]string{ + "7.15.0": `{"_shards":{"total":30,"successful":30,"failed":0},"data_stream_count":2,"backing_indices":7,"total_store_size_bytes":1103028116,"data_streams":[{"data_stream":"foo","backing_indices":5,"store_size_bytes":429205396,"maximum_timestamp":1656079894000},{"data_stream":"bar","backing_indices":2,"store_size_bytes":673822720,"maximum_timestamp":1656028796000}]}`, + } + for ver, out := range tcs { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, out) + })) + defer ts.Close() + + u, err := url.Parse(ts.URL) + if err != nil { + t.Fatalf("Failed to parse URL: %s", err) + } + s := NewDataStream(log.NewNopLogger(), http.DefaultClient, u) + stats, err := s.fetchAndDecodeDataStreamStats() + if err != nil { + t.Fatalf("Failed to fetch or decode data stream stats: %s", err) + } + t.Logf("[%s] Data Stream Response: %+v", ver, stats) + dataStreamStats := stats.DataStreamStats[0] + + if dataStreamStats.BackingIndices != 5 { + t.Errorf("Bad number of backing indices") + } + + if dataStreamStats.StoreSizeBytes != 429205396 { + t.Errorf("Bad store size bytes valuee") + } + } + +} diff --git a/collector/ilm_indices.go b/collector/ilm_indices.go new file mode 100644 index 00000000..22410b00 --- /dev/null +++ b/collector/ilm_indices.go @@ -0,0 +1,184 @@ +// Copyright 2023 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package collector + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "net/url" + "path" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/prometheus/client_golang/prometheus" +) + +type ilmMetric struct { + Type prometheus.ValueType + Desc *prometheus.Desc + Value func(timeMillis float64) float64 + Labels []string +} + +// Index Lifecycle Management information object +type IlmIndiciesCollector struct { + logger log.Logger + client *http.Client + url *url.URL + + up prometheus.Gauge + totalScrapes prometheus.Counter + jsonParseFailures prometheus.Counter + + ilmMetric ilmMetric +} + +type IlmResponse struct { + Indices map[string]IlmIndexResponse `json:"indices"` +} + +type IlmIndexResponse struct { + Index string `json:"index"` + Managed bool `json:"managed"` + Phase string `json:"phase"` + Action string `json:"action"` + Step string `json:"step"` + StepTimeMillis float64 `json:"step_time_millis"` +} + +var ( + defaultIlmIndicesMappingsLabels = []string{"index", "phase", "action", "step"} +) + +// NewIlmIndicies defines Index Lifecycle Management Prometheus metrics +func NewIlmIndicies(logger log.Logger, client *http.Client, url *url.URL) *IlmIndiciesCollector { + subsystem := "ilm_index" + + return &IlmIndiciesCollector{ + logger: logger, + client: client, + url: url, + + up: prometheus.NewGauge(prometheus.GaugeOpts{ + Name: prometheus.BuildFQName(namespace, subsystem, "up"), + Help: "Was the last scrape of the ElasticSearch ILM endpoint successful.", + }), + totalScrapes: prometheus.NewCounter(prometheus.CounterOpts{ + Name: prometheus.BuildFQName(namespace, subsystem, "total_scrapes"), + Help: "Current total ElasticSearch ILM scrapes.", + }), + jsonParseFailures: prometheus.NewCounter(prometheus.CounterOpts{ + Name: prometheus.BuildFQName(namespace, subsystem, "json_parse_failures"), + Help: "Number of errors while parsing JSON.", + }), + ilmMetric: ilmMetric{ + Type: prometheus.GaugeValue, + Desc: prometheus.NewDesc( + prometheus.BuildFQName(namespace, subsystem, "status"), + "Status of ILM policy for index", + defaultIlmIndicesMappingsLabels, nil), + Value: func(timeMillis float64) float64 { + return timeMillis + }, + }, + } +} + +// Describe adds metrics description +func (i *IlmIndiciesCollector) Describe(ch chan<- *prometheus.Desc) { + ch <- i.ilmMetric.Desc + ch <- i.up.Desc() + ch <- i.totalScrapes.Desc() + ch <- i.jsonParseFailures.Desc() +} + +func (i *IlmIndiciesCollector) fetchAndDecodeIlm() (IlmResponse, error) { + var ir IlmResponse + + u := *i.url + u.Path = path.Join(u.Path, "/_all/_ilm/explain") + + res, err := i.client.Get(u.String()) + if err != nil { + return ir, fmt.Errorf("failed to get index stats from %s://%s:%s%s: %s", + u.Scheme, u.Hostname(), u.Port(), u.Path, err) + } + + defer func() { + err = res.Body.Close() + if err != nil { + level.Warn(i.logger).Log( + "msg", "failed to close http.Client", + "err", err, + ) + } + }() + + if res.StatusCode != http.StatusOK { + return ir, fmt.Errorf("HTTP Request failed with code %d", res.StatusCode) + } + + bts, err := io.ReadAll(res.Body) + if err != nil { + i.jsonParseFailures.Inc() + return ir, err + } + + if err := json.Unmarshal(bts, &ir); err != nil { + i.jsonParseFailures.Inc() + return ir, err + } + + return ir, nil +} + +func bool2int(managed bool) float64 { + if managed { + return 1 + } + return 0 +} + +// Collect pulls metric values from Elasticsearch +func (i *IlmIndiciesCollector) Collect(ch chan<- prometheus.Metric) { + defer func() { + ch <- i.up + ch <- i.totalScrapes + ch <- i.jsonParseFailures + }() + + // indices + ilmResp, err := i.fetchAndDecodeIlm() + if err != nil { + i.up.Set(0) + level.Warn(i.logger).Log( + "msg", "failed to fetch and decode ILM stats", + "err", err, + ) + return + } + i.totalScrapes.Inc() + i.up.Set(1) + + for indexName, indexIlm := range ilmResp.Indices { + ch <- prometheus.MustNewConstMetric( + i.ilmMetric.Desc, + i.ilmMetric.Type, + i.ilmMetric.Value(bool2int(indexIlm.Managed)), + indexName, indexIlm.Phase, indexIlm.Action, indexIlm.Step, + ) + } +} diff --git a/collector/ilm_indices_test.go b/collector/ilm_indices_test.go new file mode 100644 index 00000000..27218f51 --- /dev/null +++ b/collector/ilm_indices_test.go @@ -0,0 +1,117 @@ +// Copyright 2023 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package collector + +import ( + "fmt" + "net/http" + "net/http/httptest" + "net/url" + "testing" + + "github.com/go-kit/log" +) + +func TestILMMetrics(t *testing.T) { + // Testcases created using: + // docker run -d -p 9200:9200 elasticsearch:VERSION + // curl -XPUT http://localhost:9200/twitter + // curl -X PUT "localhost:9200/_ilm/policy/my_policy?pretty" -H 'Content-Type: application/json' -d' + // { + // "policy": { + // "phases": { + // "warm": { + // "min_age": "10d", + // "actions": { + // "forcemerge": { + // "max_num_segments": 1 + // } + // } + // }, + // "delete": { + // "min_age": "30d", + // "actions": { + // "delete": {} + // } + // } + // } + // } + // } + // ' + // curl -X PUT "localhost:9200/facebook?pretty" -H 'Content-Type: application/json' -d' + // { + // "settings": { + // "index": { + // "lifecycle": { + // "name": "my_policy" + // } + // } + // } + // } + // ' + // curl http://localhost:9200/_all/_ilm/explain + tcs := map[string]string{ + "6.6.0": `{ + "indices": { + "twitter": { "index": "twitter", "managed": false }, + "facebook": { + "index": "facebook", + "managed": true, + "policy": "my_policy", + "lifecycle_date_millis": 1660799138565, + "phase": "new", + "phase_time_millis": 1660799138651, + "action": "complete", + "action_time_millis": 1660799138651, + "step": "complete", + "step_time_millis": 1660799138651 + } + } + }`, + } + for ver, out := range tcs { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, out) + })) + defer ts.Close() + + u, err := url.Parse(ts.URL) + if err != nil { + t.Fatalf("Failed to parse URL: %s", err) + } + c := NewIlmIndicies(log.NewNopLogger(), http.DefaultClient, u) + chr, err := c.fetchAndDecodeIlm() + if err != nil { + t.Fatalf("Failed to fetch or decode indices ilm metrics: %s", err) + } + t.Logf("[%s] indices ilm metrics Response: %+v", ver, chr) + + if chr.Indices["twitter"].Managed != false { + t.Errorf("Invalid ilm metrics at twitter.managed") + } + if chr.Indices["facebook"].Managed != true { + t.Errorf("Invalid ilm metrics at facebook.managed") + } + if chr.Indices["facebook"].Phase != "new" { + t.Errorf("Invalid ilm metrics at facebook.phase") + } + if chr.Indices["facebook"].Action != "complete" { + t.Errorf("Invalid ilm metrics at facebook.action") + } + if chr.Indices["facebook"].Step != "complete" { + t.Errorf("Invalid ilm metrics at facebook.step") + } + + } +} diff --git a/collector/ilm_status.go b/collector/ilm_status.go new file mode 100644 index 00000000..a00372df --- /dev/null +++ b/collector/ilm_status.go @@ -0,0 +1,167 @@ +// Copyright 2023 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package collector + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "net/url" + "path" + + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/prometheus/client_golang/prometheus" +) + +var ( + ilmStatuses = []string{"STOPPED", "RUNNING", "STOPPING"} +) + +type ilmStatusMetric struct { + Type prometheus.ValueType + Desc *prometheus.Desc + Value func(ilm *IlmStatusResponse, status string) float64 + Labels func(status string) []string +} + +// IlmStatusCollector information struct +type IlmStatusCollector struct { + logger log.Logger + client *http.Client + url *url.URL + + up prometheus.Gauge + totalScrapes, jsonParseFailures prometheus.Counter + + metric ilmStatusMetric +} + +type IlmStatusResponse struct { + OperationMode string `json:"operation_mode"` +} + +// NewIlmStatus defines Indices IndexIlms Prometheus metrics +func NewIlmStatus(logger log.Logger, client *http.Client, url *url.URL) *IlmStatusCollector { + subsystem := "ilm" + + return &IlmStatusCollector{ + logger: logger, + client: client, + url: url, + + up: prometheus.NewGauge(prometheus.GaugeOpts{ + Name: prometheus.BuildFQName(namespace, subsystem, "up"), + Help: "Was the last scrape of the ElasticSearch Indices Ilms endpoint successful.", + }), + totalScrapes: prometheus.NewCounter(prometheus.CounterOpts{ + Name: prometheus.BuildFQName(namespace, subsystem, "scrapes_total"), + Help: "Current total ElasticSearch Indices Ilms scrapes.", + }), + jsonParseFailures: prometheus.NewCounter(prometheus.CounterOpts{ + Name: prometheus.BuildFQName(namespace, subsystem, "json_parse_failures_total"), + Help: "Number of errors while parsing JSON.", + }), + metric: ilmStatusMetric{ + Type: prometheus.GaugeValue, + Desc: prometheus.NewDesc( + prometheus.BuildFQName(namespace, subsystem, "status"), + "Current status of ilm. Status can be STOPPED, RUNNING, STOPPING.", + []string{"operation_mode"}, nil, + ), + Value: func(ilm *IlmStatusResponse, status string) float64 { + if ilm.OperationMode == status { + return 1 + } + return 0 + }, + }, + } +} + +// Describe add Snapshots metrics descriptions +func (im *IlmStatusCollector) Describe(ch chan<- *prometheus.Desc) { + ch <- im.metric.Desc + ch <- im.up.Desc() + ch <- im.totalScrapes.Desc() + ch <- im.jsonParseFailures.Desc() +} + +func (im *IlmStatusCollector) fetchAndDecodeIlm() (*IlmStatusResponse, error) { + u := *im.url + u.Path = path.Join(im.url.Path, "/_ilm/status") + + res, err := im.client.Get(u.String()) + if err != nil { + return nil, fmt.Errorf("failed to get from %s://%s:%s%s: %s", + u.Scheme, u.Hostname(), u.Port(), u.Path, err) + } + + if res.StatusCode != http.StatusOK { + return nil, fmt.Errorf("HTTP Request failed with code %d", res.StatusCode) + } + + body, err := io.ReadAll(res.Body) + if err != nil { + level.Warn(im.logger).Log("msg", "failed to read response body", "err", err) + return nil, err + } + + err = res.Body.Close() + if err != nil { + level.Warn(im.logger).Log("msg", "failed to close response body", "err", err) + return nil, err + } + + var imr IlmStatusResponse + if err := json.Unmarshal(body, &imr); err != nil { + im.jsonParseFailures.Inc() + return nil, err + } + + return &imr, nil +} + +// Collect gets all indices Ilms metric values +func (im *IlmStatusCollector) Collect(ch chan<- prometheus.Metric) { + + im.totalScrapes.Inc() + defer func() { + ch <- im.up + ch <- im.totalScrapes + ch <- im.jsonParseFailures + }() + + indicesIlmsResponse, err := im.fetchAndDecodeIlm() + if err != nil { + im.up.Set(0) + level.Warn(im.logger).Log( + "msg", "failed to fetch and decode cluster ilm status", + "err", err, + ) + return + } + im.up.Set(1) + + for _, status := range ilmStatuses { + ch <- prometheus.MustNewConstMetric( + im.metric.Desc, + im.metric.Type, + im.metric.Value(indicesIlmsResponse, status), + status, + ) + } + +} diff --git a/collector/ilm_status_test.go b/collector/ilm_status_test.go new file mode 100644 index 00000000..8744eec1 --- /dev/null +++ b/collector/ilm_status_test.go @@ -0,0 +1,53 @@ +// Copyright 2023 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package collector + +import ( + "fmt" + "net/http" + "net/http/httptest" + "net/url" + "testing" + + "github.com/go-kit/log" +) + +func TestILMStatus(t *testing.T) { + // Testcases created using: + // docker run -d -p 9200:9200 elasticsearch:VERSION + // curl http://localhost:9200/_ilm/status + tcs := map[string]string{ + "6.6.0": `{ "operation_mode": "RUNNING" }`, + } + for ver, out := range tcs { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, out) + })) + defer ts.Close() + + u, err := url.Parse(ts.URL) + if err != nil { + t.Fatalf("Failed to parse URL: %s", err) + } + c := NewIlmStatus(log.NewNopLogger(), http.DefaultClient, u) + chr, err := c.fetchAndDecodeIlm() + if err != nil { + t.Fatalf("Failed to fetch or decode ilm status: %s", err) + } + t.Logf("[%s] ILM Status Response: %+v", ver, chr) + if chr.OperationMode != "RUNNING" { + t.Errorf("Invalid ilm status") + } + } +} diff --git a/collector/indices.go b/collector/indices.go index 1a4b0146..b76f6087 100644 --- a/collector/indices.go +++ b/collector/indices.go @@ -16,16 +16,16 @@ package collector import ( "encoding/json" "fmt" - "io/ioutil" - "net/http" - "net/url" - "path" - "strconv" - "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus-community/elasticsearch_exporter/pkg/clusterinfo" "github.com/prometheus/client_golang/prometheus" + "io" + "net/http" + "net/url" + "path" + "sort" + "strconv" ) type labels struct { @@ -47,12 +47,21 @@ type shardMetric struct { Labels labels } +type aliasMetric struct { + Type prometheus.ValueType + Desc *prometheus.Desc + Value func() float64 + Labels labels +} + // Indices information struct type Indices struct { logger log.Logger client *http.Client url *url.URL + indicesFilter string shards bool + aliases bool clusterInfoCh chan *clusterinfo.Response lastClusterInfo *clusterinfo.Response @@ -62,10 +71,11 @@ type Indices struct { indexMetrics []*indexMetric shardMetrics []*shardMetric + aliasMetrics []*aliasMetric } // NewIndices defines Indices Prometheus metrics -func NewIndices(logger log.Logger, client *http.Client, url *url.URL, shards bool) *Indices { +func NewIndices(logger log.Logger, client *http.Client, url *url.URL, shards bool, includeAliases bool, indicesFilter string) *Indices { indexLabels := labels{ keys: func(...string) []string { @@ -95,11 +105,27 @@ func NewIndices(logger log.Logger, client *http.Client, url *url.URL, shards boo }, } + aliasLabels := labels{ + keys: func(...string) []string { + return []string{"index", "alias", "cluster"} + }, + values: func(lastClusterinfo *clusterinfo.Response, s ...string) []string { + if lastClusterinfo != nil { + return append(s, lastClusterinfo.ClusterName) + } + // this shouldn't happen, as the clusterinfo Retriever has a blocking + // Run method. It blocks until the first clusterinfo call has succeeded + return append(s, "unknown_cluster") + }, + } + indices := &Indices{ logger: logger, client: client, url: url, + indicesFilter: indicesFilter, shards: shards, + aliases: includeAliases, clusterInfoCh: make(chan *clusterinfo.Response), lastClusterInfo: &clusterinfo.Response{ ClusterName: "unknown_cluster", @@ -107,11 +133,11 @@ func NewIndices(logger log.Logger, client *http.Client, url *url.URL, shards boo up: prometheus.NewGauge(prometheus.GaugeOpts{ Name: prometheus.BuildFQName(namespace, "index_stats", "up"), - Help: "Was the last scrape of the ElasticSearch index endpoint successful.", + Help: "Was the last scrape of the Elasticsearch index endpoint successful.", }), totalScrapes: prometheus.NewCounter(prometheus.CounterOpts{ Name: prometheus.BuildFQName(namespace, "index_stats", "total_scrapes"), - Help: "Current total ElasticSearch index scrapes.", + Help: "Current total Elasticsearch index scrapes.", }), jsonParseFailures: prometheus.NewCounter(prometheus.CounterOpts{ Name: prometheus.BuildFQName(namespace, "index_stats", "json_parse_failures"), @@ -1022,18 +1048,33 @@ func NewIndices(logger log.Logger, client *http.Client, url *url.URL, shards boo Labels: shardLabels, }, }, + + aliasMetrics: []*aliasMetric{ + { + Type: prometheus.GaugeValue, + Desc: prometheus.NewDesc( + prometheus.BuildFQName(namespace, "indices", "aliases"), + "Record aliases associated with an index", + aliasLabels.keys(), nil, + ), + Value: func() float64 { + return float64(1) + }, + Labels: aliasLabels, + }, + }, } // start go routine to fetch clusterinfo updates and save them to lastClusterinfo go func() { - _ = level.Debug(logger).Log("msg", "starting cluster info receive loop") + level.Debug(logger).Log("msg", "starting cluster info receive loop") for ci := range indices.clusterInfoCh { if ci != nil { - _ = level.Debug(logger).Log("msg", "received cluster info update", "cluster", ci.ClusterName) + level.Debug(logger).Log("msg", "received cluster info update", "cluster", ci.ClusterName) indices.lastClusterInfo = ci } } - _ = level.Debug(logger).Log("msg", "exiting cluster info receive loop") + level.Debug(logger).Log("msg", "exiting cluster info receive loop") }() return indices } @@ -1063,23 +1104,81 @@ func (i *Indices) fetchAndDecodeIndexStats() (indexStatsResponse, error) { var isr indexStatsResponse u := *i.url - u.Path = path.Join(u.Path, "/_all/_stats") + indicesStatsQueryPath := fmt.Sprintf("/%s/_stats", i.indicesFilter) + _ = level.Debug(i.logger).Log( + "msg", fmt.Sprintf("indices fetch query path: %s", indicesStatsQueryPath), + ) + u.Path = path.Join(u.Path, indicesStatsQueryPath) if i.shards { u.RawQuery = "ignore_unavailable=true&level=shards" } else { u.RawQuery = "ignore_unavailable=true" } + bts, err := i.queryURL(&u) + if err != nil { + return isr, err + } + + if err := json.Unmarshal(bts, &isr); err != nil { + i.jsonParseFailures.Inc() + return isr, err + } + + if i.aliases { + isr.Aliases = map[string][]string{} + asr, err := i.fetchAndDecodeAliases() + if err != nil { + level.Error(i.logger).Log("err", err.Error()) + return isr, err + } + + for indexName, aliases := range asr { + var aliasList []string + for aliasName := range aliases.Aliases { + aliasList = append(aliasList, aliasName) + } + + if len(aliasList) > 0 { + sort.Strings(aliasList) + isr.Aliases[indexName] = aliasList + } + } + } + + return isr, nil +} + +func (i *Indices) fetchAndDecodeAliases() (aliasesResponse, error) { + var asr aliasesResponse + + u := *i.url + u.Path = path.Join(u.Path, "/_alias") + + bts, err := i.queryURL(&u) + if err != nil { + return asr, err + } + + if err := json.Unmarshal(bts, &asr); err != nil { + i.jsonParseFailures.Inc() + return asr, err + } + + return asr, nil +} + +func (i *Indices) queryURL(u *url.URL) ([]byte, error) { res, err := i.client.Get(u.String()) if err != nil { - return isr, fmt.Errorf("failed to get index stats from %s://%s:%s%s: %s", + return []byte{}, fmt.Errorf("failed to get resource from %s://%s:%s%s: %s", u.Scheme, u.Hostname(), u.Port(), u.Path, err) } defer func() { err = res.Body.Close() if err != nil { - _ = level.Warn(i.logger).Log( + level.Warn(i.logger).Log( "msg", "failed to close http.Client", "err", err, ) @@ -1087,21 +1186,15 @@ func (i *Indices) fetchAndDecodeIndexStats() (indexStatsResponse, error) { }() if res.StatusCode != http.StatusOK { - return isr, fmt.Errorf("HTTP Request failed with code %d", res.StatusCode) + return []byte{}, fmt.Errorf("HTTP Request failed with code %d", res.StatusCode) } - bts, err := ioutil.ReadAll(res.Body) + bts, err := io.ReadAll(res.Body) if err != nil { - i.jsonParseFailures.Inc() - return isr, err - } - - if err := json.Unmarshal(bts, &isr); err != nil { - i.jsonParseFailures.Inc() - return isr, err + return []byte{}, err } - return isr, nil + return bts, nil } // Collect gets Indices metric values @@ -1117,7 +1210,7 @@ func (i *Indices) Collect(ch chan<- prometheus.Metric) { indexStatsResp, err := i.fetchAndDecodeIndexStats() if err != nil { i.up.Set(0) - _ = level.Warn(i.logger).Log( + level.Warn(i.logger).Log( "msg", "failed to fetch and decode index stats", "err", err, ) @@ -1125,6 +1218,24 @@ func (i *Indices) Collect(ch chan<- prometheus.Metric) { } i.up.Set(1) + // Alias stats + if i.aliases { + for _, metric := range i.aliasMetrics { + for indexName, aliases := range indexStatsResp.Aliases { + for _, alias := range aliases { + labelValues := metric.Labels.values(i.lastClusterInfo, indexName, alias) + + ch <- prometheus.MustNewConstMetric( + metric.Desc, + metric.Type, + metric.Value(), + labelValues..., + ) + } + } + } + } + // Index stats for indexName, indexStats := range indexStatsResp.Indices { for _, metric := range i.indexMetrics { diff --git a/collector/indices_mappings.go b/collector/indices_mappings.go index 38698bf3..577f5298 100644 --- a/collector/indices_mappings.go +++ b/collector/indices_mappings.go @@ -16,7 +16,7 @@ package collector import ( "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "net/url" "path" @@ -38,9 +38,10 @@ type indicesMappingsMetric struct { // IndicesMappings information struct type IndicesMappings struct { - logger log.Logger - client *http.Client - url *url.URL + logger log.Logger + client *http.Client + url *url.URL + indicesFilter string up prometheus.Gauge totalScrapes, jsonParseFailures prometheus.Counter @@ -49,21 +50,22 @@ type IndicesMappings struct { } // NewIndicesMappings defines Indices IndexMappings Prometheus metrics -func NewIndicesMappings(logger log.Logger, client *http.Client, url *url.URL) *IndicesMappings { +func NewIndicesMappings(logger log.Logger, client *http.Client, url *url.URL, indicesFilter string) *IndicesMappings { subsystem := "indices_mappings_stats" return &IndicesMappings{ - logger: logger, - client: client, - url: url, + logger: logger, + client: client, + url: url, + indicesFilter: indicesFilter, up: prometheus.NewGauge(prometheus.GaugeOpts{ Name: prometheus.BuildFQName(namespace, subsystem, "up"), - Help: "Was the last scrape of the ElasticSearch Indices Mappings endpoint successful.", + Help: "Was the last scrape of the Elasticsearch Indices Mappings endpoint successful.", }), totalScrapes: prometheus.NewCounter(prometheus.CounterOpts{ Name: prometheus.BuildFQName(namespace, subsystem, "scrapes_total"), - Help: "Current total ElasticSearch Indices Mappings scrapes.", + Help: "Current total Elasticsearch Indices Mappings scrapes.", }), jsonParseFailures: prometheus.NewCounter(prometheus.CounterOpts{ Name: prometheus.BuildFQName(namespace, subsystem, "json_parse_failures_total"), @@ -88,8 +90,10 @@ func NewIndicesMappings(logger log.Logger, client *http.Client, url *url.URL) *I func countFieldsRecursive(properties IndexMappingProperties, fieldCounter float64) float64 { // iterate over all properties for _, property := range properties { - if property.Type != nil { - // property has a type set - counts as a field + + if property.Type != nil && *property.Type != "object" { + // property has a type set - counts as a field unless the value is object + // as the recursion below will handle counting that fieldCounter++ // iterate over all fields of that property @@ -103,7 +107,7 @@ func countFieldsRecursive(properties IndexMappingProperties, fieldCounter float6 // count recursively in case the property has more properties if property.Properties != nil { - fieldCounter = +countFieldsRecursive(property.Properties, fieldCounter) + fieldCounter = 1 + countFieldsRecursive(property.Properties, fieldCounter) } } @@ -132,15 +136,15 @@ func (im *IndicesMappings) getAndParseURL(u *url.URL) (*IndicesMappingsResponse, return nil, fmt.Errorf("HTTP Request failed with code %d", res.StatusCode) } - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) if err != nil { - _ = level.Warn(im.logger).Log("msg", "failed to read response body", "err", err) + level.Warn(im.logger).Log("msg", "failed to read response body", "err", err) return nil, err } err = res.Body.Close() if err != nil { - _ = level.Warn(im.logger).Log("msg", "failed to close response body", "err", err) + level.Warn(im.logger).Log("msg", "failed to close response body", "err", err) return nil, err } @@ -155,7 +159,8 @@ func (im *IndicesMappings) getAndParseURL(u *url.URL) (*IndicesMappingsResponse, func (im *IndicesMappings) fetchAndDecodeIndicesMappings() (*IndicesMappingsResponse, error) { u := *im.url - u.Path = path.Join(u.Path, "/_all/_mappings") + indicesMappingsQueryPath := fmt.Sprintf("/%s/_mappings", im.indicesFilter) + u.Path = path.Join(u.Path, indicesMappingsQueryPath) return im.getAndParseURL(&u) } @@ -172,7 +177,7 @@ func (im *IndicesMappings) Collect(ch chan<- prometheus.Metric) { indicesMappingsResponse, err := im.fetchAndDecodeIndicesMappings() if err != nil { im.up.Set(0) - _ = level.Warn(im.logger).Log( + level.Warn(im.logger).Log( "msg", "failed to fetch and decode cluster mappings stats", "err", err, ) diff --git a/collector/indices_mappings_test.go b/collector/indices_mappings_test.go index 87cb3ef5..64e8d682 100644 --- a/collector/indices_mappings_test.go +++ b/collector/indices_mappings_test.go @@ -124,7 +124,7 @@ func TestMapping(t *testing.T) { if err != nil { t.Fatalf("Failed to parse URL: %s", err) } - c := NewIndicesMappings(log.NewNopLogger(), http.DefaultClient, u) + c := NewIndicesMappings(log.NewNopLogger(), http.DefaultClient, u, "_all") imr, err := c.fetchAndDecodeIndicesMappings() if err != nil { t.Fatalf("Failed to fetch or decode indices mappings: %s", err) @@ -159,3 +159,222 @@ func TestMapping(t *testing.T) { } } } + +func TestIndexMappingFieldCount(t *testing.T) { + + testIndexNumFields := 40.0 + testIndexName := "test-data-2023.01.20" + + rawMapping := `{ + "test-data-2023.01.20": { + "mappings": { + "properties": { + "data": { + "type": "object", + "properties": { + "field1": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "field10": { + "type": "long" + }, + "field2": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "field3": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "field4": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "field5": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "field6": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "field7": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "field8": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "field9": { + "type": "long" + } + } + }, + "data2": { + "properties": { + "field1": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "field2": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "field3": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "field4": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "field5": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "nested_field6": { + "properties": { + "field1": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "field2": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "field3": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "field4": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "field5": { + "type": "long" + } + } + } + } + } + } + } + } + }` + + for _, handler := range map[string]http.Handler{ + "plain": http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, rawMapping) + }), + } { + + ts := httptest.NewServer(handler) + defer ts.Close() + + u, err := url.Parse(ts.URL) + if err != nil { + t.Fatalf("Failed to parse URL: %s", err) + } + c := NewIndicesMappings(log.NewNopLogger(), http.DefaultClient, u, "_all") + indicesMappingsResponse, err := c.fetchAndDecodeIndicesMappings() + if err != nil { + t.Fatalf("Failed to fetch or decode indices mappings: %s", err) + } + + response := *indicesMappingsResponse + mapping := response[testIndexName] + totalFields := countFieldsRecursive(mapping.Mappings.Properties, 0) + if totalFields != testIndexNumFields { + t.Errorf("Number of actual fields in index doesn't match the count returned by the recursive countFieldsRecursive function") + } + + } + +} diff --git a/collector/indices_response.go b/collector/indices_response.go index 20a8823a..6638d339 100644 --- a/collector/indices_response.go +++ b/collector/indices_response.go @@ -18,6 +18,15 @@ type indexStatsResponse struct { Shards IndexStatsShardsResponse `json:"_shards"` All IndexStatsIndexResponse `json:"_all"` Indices map[string]IndexStatsIndexResponse `json:"indices"` + Aliases map[string][]string +} + +// aliasesResponse is a representation of a Elasticsearch Alias Query +type aliasesResponse map[string]aliasMapping + +// aliasMapping is a mapping of index names to a map of associated alias names where the alias names are keys +type aliasMapping struct { + Aliases map[string]map[string]interface{} `json:"aliases"` } // IndexStatsShardsResponse defines index stats shards information structure diff --git a/collector/indices_settings.go b/collector/indices_settings.go index 12fd0485..af9e9b42 100644 --- a/collector/indices_settings.go +++ b/collector/indices_settings.go @@ -16,7 +16,7 @@ package collector import ( "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "net/url" "path" @@ -29,9 +29,10 @@ import ( // IndicesSettings information struct type IndicesSettings struct { - logger log.Logger - client *http.Client - url *url.URL + logger log.Logger + client *http.Client + url *url.URL + indicesFilter string up prometheus.Gauge readOnlyIndices prometheus.Gauge @@ -52,19 +53,20 @@ type indicesSettingsMetric struct { } // NewIndicesSettings defines Indices Settings Prometheus metrics -func NewIndicesSettings(logger log.Logger, client *http.Client, url *url.URL) *IndicesSettings { +func NewIndicesSettings(logger log.Logger, client *http.Client, url *url.URL, indicesFilter string) *IndicesSettings { return &IndicesSettings{ - logger: logger, - client: client, - url: url, + logger: logger, + client: client, + url: url, + indicesFilter: indicesFilter, up: prometheus.NewGauge(prometheus.GaugeOpts{ Name: prometheus.BuildFQName(namespace, "indices_settings_stats", "up"), - Help: "Was the last scrape of the ElasticSearch Indices Settings endpoint successful.", + Help: "Was the last scrape of the Elasticsearch Indices Settings endpoint successful.", }), totalScrapes: prometheus.NewCounter(prometheus.CounterOpts{ Name: prometheus.BuildFQName(namespace, "indices_settings_stats", "total_scrapes"), - Help: "Current total ElasticSearch Indices Settings scrapes.", + Help: "Current total Elasticsearch Indices Settings scrapes.", }), readOnlyIndices: prometheus.NewGauge(prometheus.GaugeOpts{ Name: prometheus.BuildFQName(namespace, "indices_settings_stats", "read_only_indices"), @@ -90,6 +92,21 @@ func NewIndicesSettings(logger log.Logger, client *http.Client, url *url.URL) *I return val }, }, + { + Type: prometheus.GaugeValue, + Desc: prometheus.NewDesc( + prometheus.BuildFQName(namespace, "indices_settings", "replicas"), + "index setting number_of_replicas", + defaultIndicesTotalFieldsLabels, nil, + ), + Value: func(indexSettings Settings) float64 { + val, err := strconv.ParseFloat(indexSettings.IndexInfo.NumberOfReplicas, 64) + if err != nil { + return float64(defaultTotalFieldsValue) + } + return val + }, + }, }, } } @@ -112,7 +129,7 @@ func (cs *IndicesSettings) getAndParseURL(u *url.URL, data interface{}) error { defer func() { err = res.Body.Close() if err != nil { - _ = level.Warn(cs.logger).Log( + level.Warn(cs.logger).Log( "msg", "failed to close http.Client", "err", err, ) @@ -123,7 +140,7 @@ func (cs *IndicesSettings) getAndParseURL(u *url.URL, data interface{}) error { return fmt.Errorf("HTTP Request failed with code %d", res.StatusCode) } - bts, err := ioutil.ReadAll(res.Body) + bts, err := io.ReadAll(res.Body) if err != nil { cs.jsonParseFailures.Inc() return err @@ -139,7 +156,8 @@ func (cs *IndicesSettings) getAndParseURL(u *url.URL, data interface{}) error { func (cs *IndicesSettings) fetchAndDecodeIndicesSettings() (IndicesSettingsResponse, error) { u := *cs.url - u.Path = path.Join(u.Path, "/_all/_settings") + indicesSettingsQueryPath := fmt.Sprintf("/%s/_settings", cs.indicesFilter) + u.Path = path.Join(u.Path, indicesSettingsQueryPath) var asr IndicesSettingsResponse err := cs.getAndParseURL(&u, &asr) if err != nil { @@ -164,7 +182,7 @@ func (cs *IndicesSettings) Collect(ch chan<- prometheus.Metric) { if err != nil { cs.readOnlyIndices.Set(0) cs.up.Set(0) - _ = level.Warn(cs.logger).Log( + level.Warn(cs.logger).Log( "msg", "failed to fetch and decode cluster settings stats", "err", err, ) diff --git a/collector/indices_settings_response.go b/collector/indices_settings_response.go index b7350677..1a7f8c2f 100644 --- a/collector/indices_settings_response.go +++ b/collector/indices_settings_response.go @@ -28,8 +28,9 @@ type Settings struct { // IndexInfo defines the blocks of the current index type IndexInfo struct { - Blocks Blocks `json:"blocks"` - Mapping Mapping `json:"mapping"` + Blocks Blocks `json:"blocks"` + Mapping Mapping `json:"mapping"` + NumberOfReplicas string `json:"number_of_replicas"` } // Blocks defines whether current index has read_only_allow_delete enabled diff --git a/collector/indices_settings_test.go b/collector/indices_settings_test.go index 7a3d0fcd..a16f360f 100644 --- a/collector/indices_settings_test.go +++ b/collector/indices_settings_test.go @@ -70,7 +70,7 @@ func TestIndicesSettings(t *testing.T) { if err != nil { t.Fatalf("Failed to parse URL: %s", err) } - c := NewIndicesSettings(log.NewNopLogger(), http.DefaultClient, u) + c := NewIndicesSettings(log.NewNopLogger(), http.DefaultClient, u, "_all") nsr, err := c.fetchAndDecodeIndicesSettings() if err != nil { t.Fatalf("Failed to fetch or decode indices settings: %s", err) diff --git a/collector/indices_test.go b/collector/indices_test.go index 7f038f8d..d325d645 100644 --- a/collector/indices_test.go +++ b/collector/indices_test.go @@ -18,6 +18,7 @@ import ( "net/http" "net/http/httptest" "net/url" + "reflect" "testing" "github.com/go-kit/log" @@ -48,7 +49,7 @@ func TestIndices(t *testing.T) { if err != nil { t.Fatalf("Failed to parse URL: %s", err) } - i := NewIndices(log.NewNopLogger(), http.DefaultClient, u, false) + i := NewIndices(log.NewNopLogger(), http.DefaultClient, u, false, false, "_all") stats, err := i.fetchAndDecodeIndexStats() if err != nil { t.Fatalf("Failed to fetch or decode indices stats: %s", err) @@ -69,5 +70,73 @@ func TestIndices(t *testing.T) { if stats.Indices["foo_1"].Total.Indexing.IndexTotal == 0 { t.Errorf("Wrong indexing total recorded") } + if stats.Aliases != nil { + t.Errorf("Aliases are populated when they should not be") + } + } +} + +func TestAliases(t *testing.T) { + /* + Testcases created using (note: the docker image name no longer has -alpine in it for newer versions): + docker run -d -p 9200:9200 elasticsearch:VERSION-alpine # versions 1.x.x, 2.x.x, and 5.x.x + docker run -p 9200:9200 -e "discovery.type=single-node" elasticsearch:VERSION # version 7.x.x + curl -XPUT -H "Content-Type: application/json" http://localhost:9200/foo_1/type1/1 -d '{"title":"abc","content":"hello"}' + curl -XPUT -H "Content-Type: application/json" http://localhost:9200/foo_2/type1/1 -d '{"title":"abc001","content":"hello001"}' + curl -XPUT -H "Content-Type: application/json" http://localhost:9200/foo_3/type1/1 -d '{"title":"def003","content":"world003"}' + curl -XPOST -H "Content-Type: application/json" http://localhost:9200/_aliases -d '{"actions": [{"add": {"index": "foo_2","alias": "foo_alias_2_1"}}]}' + curl -XPOST -H "Content-Type: application/json" http://localhost:9200/_aliases -d '{"actions": [{"add": {"index": "foo_3","alias": "foo_alias_3_2"}}]}' + curl -XPOST -H "Content-Type: application/json" http://localhost:9200/_aliases -d '{"actions": [{"add": {"index": "foo_3","alias": "foo_alias_3_1", "is_write_index": true, "routing": "title"}}]}' + curl -H "Content-Type: application/json" http://localhost:9200/_alias + curl -H "Content-Type: application/json" http://localhost:9200/_all/_stats + */ + ti := map[string]map[string]string{ + "1.7.6": { + "alias": `{"foo_1":{"aliases":{}},"foo_2":{"aliases":{"foo_alias_2_1":{}}},"foo_3":{"aliases":{"foo_alias_3_1":{"index_routing":"title","search_routing":"title","is_write_index":true},"foo_alias_3_2":{}}}}`, + "stats": `{"_shards":{"total":30,"successful":15,"failed":0},"_all":{"primaries":{"docs":{"count":3,"deleted":0},"store":{"size_in_bytes":9336,"throttle_time_in_millis":0},"indexing":{"index_total":3,"index_time_in_millis":69,"index_current":0,"delete_total":0,"delete_time_in_millis":0,"delete_current":0,"noop_update_total":0,"is_throttled":false,"throttle_time_in_millis":0},"get":{"total":0,"time_in_millis":0,"exists_total":0,"exists_time_in_millis":0,"missing_total":0,"missing_time_in_millis":0,"current":0},"search":{"open_contexts":0,"query_total":0,"query_time_in_millis":0,"query_current":0,"fetch_total":0,"fetch_time_in_millis":0,"fetch_current":0},"merges":{"current":0,"current_docs":0,"current_size_in_bytes":0,"total":0,"total_time_in_millis":0,"total_docs":0,"total_size_in_bytes":0},"refresh":{"total":3,"total_time_in_millis":129},"flush":{"total":0,"total_time_in_millis":0},"warmer":{"current":0,"total":36,"total_time_in_millis":20},"filter_cache":{"memory_size_in_bytes":0,"evictions":0},"id_cache":{"memory_size_in_bytes":0},"fielddata":{"memory_size_in_bytes":0,"evictions":0},"percolate":{"total":0,"time_in_millis":0,"current":0,"memory_size_in_bytes":-1,"memory_size":"-1b","queries":0},"completion":{"size_in_bytes":0},"segments":{"count":3,"memory_in_bytes":11046,"index_writer_memory_in_bytes":0,"index_writer_max_memory_in_bytes":1006632960,"version_map_memory_in_bytes":0,"fixed_bit_set_memory_in_bytes":0},"translog":{"operations":3,"size_in_bytes":17},"suggest":{"total":0,"time_in_millis":0,"current":0},"query_cache":{"memory_size_in_bytes":0,"evictions":0,"hit_count":0,"miss_count":0},"recovery":{"current_as_source":0,"current_as_target":0,"throttle_time_in_millis":0}},"total":{"docs":{"count":3,"deleted":0},"store":{"size_in_bytes":9336,"throttle_time_in_millis":0},"indexing":{"index_total":3,"index_time_in_millis":69,"index_current":0,"delete_total":0,"delete_time_in_millis":0,"delete_current":0,"noop_update_total":0,"is_throttled":false,"throttle_time_in_millis":0},"get":{"total":0,"time_in_millis":0,"exists_total":0,"exists_time_in_millis":0,"missing_total":0,"missing_time_in_millis":0,"current":0},"search":{"open_contexts":0,"query_total":0,"query_time_in_millis":0,"query_current":0,"fetch_total":0,"fetch_time_in_millis":0,"fetch_current":0},"merges":{"current":0,"current_docs":0,"current_size_in_bytes":0,"total":0,"total_time_in_millis":0,"total_docs":0,"total_size_in_bytes":0},"refresh":{"total":3,"total_time_in_millis":129},"flush":{"total":0,"total_time_in_millis":0},"warmer":{"current":0,"total":36,"total_time_in_millis":20},"filter_cache":{"memory_size_in_bytes":0,"evictions":0},"id_cache":{"memory_size_in_bytes":0},"fielddata":{"memory_size_in_bytes":0,"evictions":0},"percolate":{"total":0,"time_in_millis":0,"current":0,"memory_size_in_bytes":-1,"memory_size":"-1b","queries":0},"completion":{"size_in_bytes":0},"segments":{"count":3,"memory_in_bytes":11046,"index_writer_memory_in_bytes":0,"index_writer_max_memory_in_bytes":1006632960,"version_map_memory_in_bytes":0,"fixed_bit_set_memory_in_bytes":0},"translog":{"operations":3,"size_in_bytes":17},"suggest":{"total":0,"time_in_millis":0,"current":0},"query_cache":{"memory_size_in_bytes":0,"evictions":0,"hit_count":0,"miss_count":0},"recovery":{"current_as_source":0,"current_as_target":0,"throttle_time_in_millis":0}}},"indices":{"foo_2":{"primaries":{"docs":{"count":1,"deleted":0},"store":{"size_in_bytes":3124,"throttle_time_in_millis":0},"indexing":{"index_total":1,"index_time_in_millis":2,"index_current":0,"delete_total":0,"delete_time_in_millis":0,"delete_current":0,"noop_update_total":0,"is_throttled":false,"throttle_time_in_millis":0},"get":{"total":0,"time_in_millis":0,"exists_total":0,"exists_time_in_millis":0,"missing_total":0,"missing_time_in_millis":0,"current":0},"search":{"open_contexts":0,"query_total":0,"query_time_in_millis":0,"query_current":0,"fetch_total":0,"fetch_time_in_millis":0,"fetch_current":0},"merges":{"current":0,"current_docs":0,"current_size_in_bytes":0,"total":0,"total_time_in_millis":0,"total_docs":0,"total_size_in_bytes":0},"refresh":{"total":1,"total_time_in_millis":14},"flush":{"total":0,"total_time_in_millis":0},"warmer":{"current":0,"total":12,"total_time_in_millis":0},"filter_cache":{"memory_size_in_bytes":0,"evictions":0},"id_cache":{"memory_size_in_bytes":0},"fielddata":{"memory_size_in_bytes":0,"evictions":0},"percolate":{"total":0,"time_in_millis":0,"current":0,"memory_size_in_bytes":-1,"memory_size":"-1b","queries":0},"completion":{"size_in_bytes":0},"segments":{"count":1,"memory_in_bytes":3682,"index_writer_memory_in_bytes":0,"index_writer_max_memory_in_bytes":335544320,"version_map_memory_in_bytes":0,"fixed_bit_set_memory_in_bytes":0},"translog":{"operations":1,"size_in_bytes":17},"suggest":{"total":0,"time_in_millis":0,"current":0},"query_cache":{"memory_size_in_bytes":0,"evictions":0,"hit_count":0,"miss_count":0},"recovery":{"current_as_source":0,"current_as_target":0,"throttle_time_in_millis":0}},"total":{"docs":{"count":1,"deleted":0},"store":{"size_in_bytes":3124,"throttle_time_in_millis":0},"indexing":{"index_total":1,"index_time_in_millis":2,"index_current":0,"delete_total":0,"delete_time_in_millis":0,"delete_current":0,"noop_update_total":0,"is_throttled":false,"throttle_time_in_millis":0},"get":{"total":0,"time_in_millis":0,"exists_total":0,"exists_time_in_millis":0,"missing_total":0,"missing_time_in_millis":0,"current":0},"search":{"open_contexts":0,"query_total":0,"query_time_in_millis":0,"query_current":0,"fetch_total":0,"fetch_time_in_millis":0,"fetch_current":0},"merges":{"current":0,"current_docs":0,"current_size_in_bytes":0,"total":0,"total_time_in_millis":0,"total_docs":0,"total_size_in_bytes":0},"refresh":{"total":1,"total_time_in_millis":14},"flush":{"total":0,"total_time_in_millis":0},"warmer":{"current":0,"total":12,"total_time_in_millis":0},"filter_cache":{"memory_size_in_bytes":0,"evictions":0},"id_cache":{"memory_size_in_bytes":0},"fielddata":{"memory_size_in_bytes":0,"evictions":0},"percolate":{"total":0,"time_in_millis":0,"current":0,"memory_size_in_bytes":-1,"memory_size":"-1b","queries":0},"completion":{"size_in_bytes":0},"segments":{"count":1,"memory_in_bytes":3682,"index_writer_memory_in_bytes":0,"index_writer_max_memory_in_bytes":335544320,"version_map_memory_in_bytes":0,"fixed_bit_set_memory_in_bytes":0},"translog":{"operations":1,"size_in_bytes":17},"suggest":{"total":0,"time_in_millis":0,"current":0},"query_cache":{"memory_size_in_bytes":0,"evictions":0,"hit_count":0,"miss_count":0},"recovery":{"current_as_source":0,"current_as_target":0,"throttle_time_in_millis":0}}},"foo_1":{"primaries":{"docs":{"count":1,"deleted":0},"store":{"size_in_bytes":3088,"throttle_time_in_millis":0},"indexing":{"index_total":1,"index_time_in_millis":65,"index_current":0,"delete_total":0,"delete_time_in_millis":0,"delete_current":0,"noop_update_total":0,"is_throttled":false,"throttle_time_in_millis":0},"get":{"total":0,"time_in_millis":0,"exists_total":0,"exists_time_in_millis":0,"missing_total":0,"missing_time_in_millis":0,"current":0},"search":{"open_contexts":0,"query_total":0,"query_time_in_millis":0,"query_current":0,"fetch_total":0,"fetch_time_in_millis":0,"fetch_current":0},"merges":{"current":0,"current_docs":0,"current_size_in_bytes":0,"total":0,"total_time_in_millis":0,"total_docs":0,"total_size_in_bytes":0},"refresh":{"total":1,"total_time_in_millis":101},"flush":{"total":0,"total_time_in_millis":0},"warmer":{"current":0,"total":12,"total_time_in_millis":20},"filter_cache":{"memory_size_in_bytes":0,"evictions":0},"id_cache":{"memory_size_in_bytes":0},"fielddata":{"memory_size_in_bytes":0,"evictions":0},"percolate":{"total":0,"time_in_millis":0,"current":0,"memory_size_in_bytes":-1,"memory_size":"-1b","queries":0},"completion":{"size_in_bytes":0},"segments":{"count":1,"memory_in_bytes":3682,"index_writer_memory_in_bytes":0,"index_writer_max_memory_in_bytes":335544320,"version_map_memory_in_bytes":0,"fixed_bit_set_memory_in_bytes":0},"translog":{"operations":1,"size_in_bytes":17},"suggest":{"total":0,"time_in_millis":0,"current":0},"query_cache":{"memory_size_in_bytes":0,"evictions":0,"hit_count":0,"miss_count":0},"recovery":{"current_as_source":0,"current_as_target":0,"throttle_time_in_millis":0}},"total":{"docs":{"count":1,"deleted":0},"store":{"size_in_bytes":3088,"throttle_time_in_millis":0},"indexing":{"index_total":1,"index_time_in_millis":65,"index_current":0,"delete_total":0,"delete_time_in_millis":0,"delete_current":0,"noop_update_total":0,"is_throttled":false,"throttle_time_in_millis":0},"get":{"total":0,"time_in_millis":0,"exists_total":0,"exists_time_in_millis":0,"missing_total":0,"missing_time_in_millis":0,"current":0},"search":{"open_contexts":0,"query_total":0,"query_time_in_millis":0,"query_current":0,"fetch_total":0,"fetch_time_in_millis":0,"fetch_current":0},"merges":{"current":0,"current_docs":0,"current_size_in_bytes":0,"total":0,"total_time_in_millis":0,"total_docs":0,"total_size_in_bytes":0},"refresh":{"total":1,"total_time_in_millis":101},"flush":{"total":0,"total_time_in_millis":0},"warmer":{"current":0,"total":12,"total_time_in_millis":20},"filter_cache":{"memory_size_in_bytes":0,"evictions":0},"id_cache":{"memory_size_in_bytes":0},"fielddata":{"memory_size_in_bytes":0,"evictions":0},"percolate":{"total":0,"time_in_millis":0,"current":0,"memory_size_in_bytes":-1,"memory_size":"-1b","queries":0},"completion":{"size_in_bytes":0},"segments":{"count":1,"memory_in_bytes":3682,"index_writer_memory_in_bytes":0,"index_writer_max_memory_in_bytes":335544320,"version_map_memory_in_bytes":0,"fixed_bit_set_memory_in_bytes":0},"translog":{"operations":1,"size_in_bytes":17},"suggest":{"total":0,"time_in_millis":0,"current":0},"query_cache":{"memory_size_in_bytes":0,"evictions":0,"hit_count":0,"miss_count":0},"recovery":{"current_as_source":0,"current_as_target":0,"throttle_time_in_millis":0}}},"foo_3":{"primaries":{"docs":{"count":1,"deleted":0},"store":{"size_in_bytes":3124,"throttle_time_in_millis":0},"indexing":{"index_total":1,"index_time_in_millis":2,"index_current":0,"delete_total":0,"delete_time_in_millis":0,"delete_current":0,"noop_update_total":0,"is_throttled":false,"throttle_time_in_millis":0},"get":{"total":0,"time_in_millis":0,"exists_total":0,"exists_time_in_millis":0,"missing_total":0,"missing_time_in_millis":0,"current":0},"search":{"open_contexts":0,"query_total":0,"query_time_in_millis":0,"query_current":0,"fetch_total":0,"fetch_time_in_millis":0,"fetch_current":0},"merges":{"current":0,"current_docs":0,"current_size_in_bytes":0,"total":0,"total_time_in_millis":0,"total_docs":0,"total_size_in_bytes":0},"refresh":{"total":1,"total_time_in_millis":14},"flush":{"total":0,"total_time_in_millis":0},"warmer":{"current":0,"total":12,"total_time_in_millis":0},"filter_cache":{"memory_size_in_bytes":0,"evictions":0},"id_cache":{"memory_size_in_bytes":0},"fielddata":{"memory_size_in_bytes":0,"evictions":0},"percolate":{"total":0,"time_in_millis":0,"current":0,"memory_size_in_bytes":-1,"memory_size":"-1b","queries":0},"completion":{"size_in_bytes":0},"segments":{"count":1,"memory_in_bytes":3682,"index_writer_memory_in_bytes":0,"index_writer_max_memory_in_bytes":335544320,"version_map_memory_in_bytes":0,"fixed_bit_set_memory_in_bytes":0},"translog":{"operations":1,"size_in_bytes":17},"suggest":{"total":0,"time_in_millis":0,"current":0},"query_cache":{"memory_size_in_bytes":0,"evictions":0,"hit_count":0,"miss_count":0},"recovery":{"current_as_source":0,"current_as_target":0,"throttle_time_in_millis":0}},"total":{"docs":{"count":1,"deleted":0},"store":{"size_in_bytes":3124,"throttle_time_in_millis":0},"indexing":{"index_total":1,"index_time_in_millis":2,"index_current":0,"delete_total":0,"delete_time_in_millis":0,"delete_current":0,"noop_update_total":0,"is_throttled":false,"throttle_time_in_millis":0},"get":{"total":0,"time_in_millis":0,"exists_total":0,"exists_time_in_millis":0,"missing_total":0,"missing_time_in_millis":0,"current":0},"search":{"open_contexts":0,"query_total":0,"query_time_in_millis":0,"query_current":0,"fetch_total":0,"fetch_time_in_millis":0,"fetch_current":0},"merges":{"current":0,"current_docs":0,"current_size_in_bytes":0,"total":0,"total_time_in_millis":0,"total_docs":0,"total_size_in_bytes":0},"refresh":{"total":1,"total_time_in_millis":14},"flush":{"total":0,"total_time_in_millis":0},"warmer":{"current":0,"total":12,"total_time_in_millis":0},"filter_cache":{"memory_size_in_bytes":0,"evictions":0},"id_cache":{"memory_size_in_bytes":0},"fielddata":{"memory_size_in_bytes":0,"evictions":0},"percolate":{"total":0,"time_in_millis":0,"current":0,"memory_size_in_bytes":-1,"memory_size":"-1b","queries":0},"completion":{"size_in_bytes":0},"segments":{"count":1,"memory_in_bytes":3682,"index_writer_memory_in_bytes":0,"index_writer_max_memory_in_bytes":335544320,"version_map_memory_in_bytes":0,"fixed_bit_set_memory_in_bytes":0},"translog":{"operations":1,"size_in_bytes":17},"suggest":{"total":0,"time_in_millis":0,"current":0},"query_cache":{"memory_size_in_bytes":0,"evictions":0,"hit_count":0,"miss_count":0},"recovery":{"current_as_source":0,"current_as_target":0,"throttle_time_in_millis":0}}}}}`, + }, + "2.4.5": { + "alias": `{"foo_1":{"aliases":{}},"foo_2":{"aliases":{"foo_alias_2_1":{}}},"foo_3":{"aliases":{"foo_alias_3_1":{"index_routing":"title","search_routing":"title","is_write_index":true},"foo_alias_3_2":{}}}}`, + "stats": `{"_shards":{"total":30,"successful":15,"failed":0},"_all":{"primaries":{"docs":{"count":3,"deleted":0},"store":{"size_in_bytes":11164,"throttle_time_in_millis":0},"indexing":{"index_total":3,"index_time_in_millis":59,"index_current":0,"index_failed":0,"delete_total":0,"delete_time_in_millis":0,"delete_current":0,"noop_update_total":0,"is_throttled":false,"throttle_time_in_millis":0},"get":{"total":0,"time_in_millis":0,"exists_total":0,"exists_time_in_millis":0,"missing_total":0,"missing_time_in_millis":0,"current":0},"search":{"open_contexts":0,"query_total":0,"query_time_in_millis":0,"query_current":0,"fetch_total":0,"fetch_time_in_millis":0,"fetch_current":0,"scroll_total":0,"scroll_time_in_millis":0,"scroll_current":0},"merges":{"current":0,"current_docs":0,"current_size_in_bytes":0,"total":0,"total_time_in_millis":0,"total_docs":0,"total_size_in_bytes":0,"total_stopped_time_in_millis":0,"total_throttled_time_in_millis":0,"total_auto_throttle_in_bytes":314572800},"refresh":{"total":3,"total_time_in_millis":148},"flush":{"total":0,"total_time_in_millis":0},"warmer":{"current":0,"total":36,"total_time_in_millis":13},"query_cache":{"memory_size_in_bytes":0,"total_count":0,"hit_count":0,"miss_count":0,"cache_size":0,"cache_count":0,"evictions":0},"fielddata":{"memory_size_in_bytes":0,"evictions":0},"percolate":{"total":0,"time_in_millis":0,"current":0,"memory_size_in_bytes":-1,"memory_size":"-1b","queries":0},"completion":{"size_in_bytes":0},"segments":{"count":3,"memory_in_bytes":6318,"terms_memory_in_bytes":4530,"stored_fields_memory_in_bytes":936,"term_vectors_memory_in_bytes":0,"norms_memory_in_bytes":576,"doc_values_memory_in_bytes":276,"index_writer_memory_in_bytes":0,"index_writer_max_memory_in_bytes":103795905,"version_map_memory_in_bytes":0,"fixed_bit_set_memory_in_bytes":0},"translog":{"operations":3,"size_in_bytes":894},"suggest":{"total":0,"time_in_millis":0,"current":0},"request_cache":{"memory_size_in_bytes":0,"evictions":0,"hit_count":0,"miss_count":0},"recovery":{"current_as_source":0,"current_as_target":0,"throttle_time_in_millis":0}},"total":{"docs":{"count":3,"deleted":0},"store":{"size_in_bytes":11164,"throttle_time_in_millis":0},"indexing":{"index_total":3,"index_time_in_millis":59,"index_current":0,"index_failed":0,"delete_total":0,"delete_time_in_millis":0,"delete_current":0,"noop_update_total":0,"is_throttled":false,"throttle_time_in_millis":0},"get":{"total":0,"time_in_millis":0,"exists_total":0,"exists_time_in_millis":0,"missing_total":0,"missing_time_in_millis":0,"current":0},"search":{"open_contexts":0,"query_total":0,"query_time_in_millis":0,"query_current":0,"fetch_total":0,"fetch_time_in_millis":0,"fetch_current":0,"scroll_total":0,"scroll_time_in_millis":0,"scroll_current":0},"merges":{"current":0,"current_docs":0,"current_size_in_bytes":0,"total":0,"total_time_in_millis":0,"total_docs":0,"total_size_in_bytes":0,"total_stopped_time_in_millis":0,"total_throttled_time_in_millis":0,"total_auto_throttle_in_bytes":314572800},"refresh":{"total":3,"total_time_in_millis":148},"flush":{"total":0,"total_time_in_millis":0},"warmer":{"current":0,"total":36,"total_time_in_millis":13},"query_cache":{"memory_size_in_bytes":0,"total_count":0,"hit_count":0,"miss_count":0,"cache_size":0,"cache_count":0,"evictions":0},"fielddata":{"memory_size_in_bytes":0,"evictions":0},"percolate":{"total":0,"time_in_millis":0,"current":0,"memory_size_in_bytes":-1,"memory_size":"-1b","queries":0},"completion":{"size_in_bytes":0},"segments":{"count":3,"memory_in_bytes":6318,"terms_memory_in_bytes":4530,"stored_fields_memory_in_bytes":936,"term_vectors_memory_in_bytes":0,"norms_memory_in_bytes":576,"doc_values_memory_in_bytes":276,"index_writer_memory_in_bytes":0,"index_writer_max_memory_in_bytes":103795905,"version_map_memory_in_bytes":0,"fixed_bit_set_memory_in_bytes":0},"translog":{"operations":3,"size_in_bytes":894},"suggest":{"total":0,"time_in_millis":0,"current":0},"request_cache":{"memory_size_in_bytes":0,"evictions":0,"hit_count":0,"miss_count":0},"recovery":{"current_as_source":0,"current_as_target":0,"throttle_time_in_millis":0}}},"indices":{"foo_2":{"primaries":{"docs":{"count":1,"deleted":0},"store":{"size_in_bytes":3733,"throttle_time_in_millis":0},"indexing":{"index_total":1,"index_time_in_millis":2,"index_current":0,"index_failed":0,"delete_total":0,"delete_time_in_millis":0,"delete_current":0,"noop_update_total":0,"is_throttled":false,"throttle_time_in_millis":0},"get":{"total":0,"time_in_millis":0,"exists_total":0,"exists_time_in_millis":0,"missing_total":0,"missing_time_in_millis":0,"current":0},"search":{"open_contexts":0,"query_total":0,"query_time_in_millis":0,"query_current":0,"fetch_total":0,"fetch_time_in_millis":0,"fetch_current":0,"scroll_total":0,"scroll_time_in_millis":0,"scroll_current":0},"merges":{"current":0,"current_docs":0,"current_size_in_bytes":0,"total":0,"total_time_in_millis":0,"total_docs":0,"total_size_in_bytes":0,"total_stopped_time_in_millis":0,"total_throttled_time_in_millis":0,"total_auto_throttle_in_bytes":104857600},"refresh":{"total":1,"total_time_in_millis":16},"flush":{"total":0,"total_time_in_millis":0},"warmer":{"current":0,"total":12,"total_time_in_millis":0},"query_cache":{"memory_size_in_bytes":0,"total_count":0,"hit_count":0,"miss_count":0,"cache_size":0,"cache_count":0,"evictions":0},"fielddata":{"memory_size_in_bytes":0,"evictions":0},"percolate":{"total":0,"time_in_millis":0,"current":0,"memory_size_in_bytes":-1,"memory_size":"-1b","queries":0},"completion":{"size_in_bytes":0},"segments":{"count":1,"memory_in_bytes":2106,"terms_memory_in_bytes":1510,"stored_fields_memory_in_bytes":312,"term_vectors_memory_in_bytes":0,"norms_memory_in_bytes":192,"doc_values_memory_in_bytes":92,"index_writer_memory_in_bytes":0,"index_writer_max_memory_in_bytes":34598635,"version_map_memory_in_bytes":0,"fixed_bit_set_memory_in_bytes":0},"translog":{"operations":1,"size_in_bytes":300},"suggest":{"total":0,"time_in_millis":0,"current":0},"request_cache":{"memory_size_in_bytes":0,"evictions":0,"hit_count":0,"miss_count":0},"recovery":{"current_as_source":0,"current_as_target":0,"throttle_time_in_millis":0}},"total":{"docs":{"count":1,"deleted":0},"store":{"size_in_bytes":3733,"throttle_time_in_millis":0},"indexing":{"index_total":1,"index_time_in_millis":2,"index_current":0,"index_failed":0,"delete_total":0,"delete_time_in_millis":0,"delete_current":0,"noop_update_total":0,"is_throttled":false,"throttle_time_in_millis":0},"get":{"total":0,"time_in_millis":0,"exists_total":0,"exists_time_in_millis":0,"missing_total":0,"missing_time_in_millis":0,"current":0},"search":{"open_contexts":0,"query_total":0,"query_time_in_millis":0,"query_current":0,"fetch_total":0,"fetch_time_in_millis":0,"fetch_current":0,"scroll_total":0,"scroll_time_in_millis":0,"scroll_current":0},"merges":{"current":0,"current_docs":0,"current_size_in_bytes":0,"total":0,"total_time_in_millis":0,"total_docs":0,"total_size_in_bytes":0,"total_stopped_time_in_millis":0,"total_throttled_time_in_millis":0,"total_auto_throttle_in_bytes":104857600},"refresh":{"total":1,"total_time_in_millis":16},"flush":{"total":0,"total_time_in_millis":0},"warmer":{"current":0,"total":12,"total_time_in_millis":0},"query_cache":{"memory_size_in_bytes":0,"total_count":0,"hit_count":0,"miss_count":0,"cache_size":0,"cache_count":0,"evictions":0},"fielddata":{"memory_size_in_bytes":0,"evictions":0},"percolate":{"total":0,"time_in_millis":0,"current":0,"memory_size_in_bytes":-1,"memory_size":"-1b","queries":0},"completion":{"size_in_bytes":0},"segments":{"count":1,"memory_in_bytes":2106,"terms_memory_in_bytes":1510,"stored_fields_memory_in_bytes":312,"term_vectors_memory_in_bytes":0,"norms_memory_in_bytes":192,"doc_values_memory_in_bytes":92,"index_writer_memory_in_bytes":0,"index_writer_max_memory_in_bytes":34598635,"version_map_memory_in_bytes":0,"fixed_bit_set_memory_in_bytes":0},"translog":{"operations":1,"size_in_bytes":300},"suggest":{"total":0,"time_in_millis":0,"current":0},"request_cache":{"memory_size_in_bytes":0,"evictions":0,"hit_count":0,"miss_count":0},"recovery":{"current_as_source":0,"current_as_target":0,"throttle_time_in_millis":0}}},"foo_1":{"primaries":{"docs":{"count":1,"deleted":0},"store":{"size_in_bytes":3698,"throttle_time_in_millis":0},"indexing":{"index_total":1,"index_time_in_millis":56,"index_current":0,"index_failed":0,"delete_total":0,"delete_time_in_millis":0,"delete_current":0,"noop_update_total":0,"is_throttled":false,"throttle_time_in_millis":0},"get":{"total":0,"time_in_millis":0,"exists_total":0,"exists_time_in_millis":0,"missing_total":0,"missing_time_in_millis":0,"current":0},"search":{"open_contexts":0,"query_total":0,"query_time_in_millis":0,"query_current":0,"fetch_total":0,"fetch_time_in_millis":0,"fetch_current":0,"scroll_total":0,"scroll_time_in_millis":0,"scroll_current":0},"merges":{"current":0,"current_docs":0,"current_size_in_bytes":0,"total":0,"total_time_in_millis":0,"total_docs":0,"total_size_in_bytes":0,"total_stopped_time_in_millis":0,"total_throttled_time_in_millis":0,"total_auto_throttle_in_bytes":104857600},"refresh":{"total":1,"total_time_in_millis":116},"flush":{"total":0,"total_time_in_millis":0},"warmer":{"current":0,"total":12,"total_time_in_millis":13},"query_cache":{"memory_size_in_bytes":0,"total_count":0,"hit_count":0,"miss_count":0,"cache_size":0,"cache_count":0,"evictions":0},"fielddata":{"memory_size_in_bytes":0,"evictions":0},"percolate":{"total":0,"time_in_millis":0,"current":0,"memory_size_in_bytes":-1,"memory_size":"-1b","queries":0},"completion":{"size_in_bytes":0},"segments":{"count":1,"memory_in_bytes":2106,"terms_memory_in_bytes":1510,"stored_fields_memory_in_bytes":312,"term_vectors_memory_in_bytes":0,"norms_memory_in_bytes":192,"doc_values_memory_in_bytes":92,"index_writer_memory_in_bytes":0,"index_writer_max_memory_in_bytes":34598635,"version_map_memory_in_bytes":0,"fixed_bit_set_memory_in_bytes":0},"translog":{"operations":1,"size_in_bytes":294},"suggest":{"total":0,"time_in_millis":0,"current":0},"request_cache":{"memory_size_in_bytes":0,"evictions":0,"hit_count":0,"miss_count":0},"recovery":{"current_as_source":0,"current_as_target":0,"throttle_time_in_millis":0}},"total":{"docs":{"count":1,"deleted":0},"store":{"size_in_bytes":3698,"throttle_time_in_millis":0},"indexing":{"index_total":1,"index_time_in_millis":56,"index_current":0,"index_failed":0,"delete_total":0,"delete_time_in_millis":0,"delete_current":0,"noop_update_total":0,"is_throttled":false,"throttle_time_in_millis":0},"get":{"total":0,"time_in_millis":0,"exists_total":0,"exists_time_in_millis":0,"missing_total":0,"missing_time_in_millis":0,"current":0},"search":{"open_contexts":0,"query_total":0,"query_time_in_millis":0,"query_current":0,"fetch_total":0,"fetch_time_in_millis":0,"fetch_current":0,"scroll_total":0,"scroll_time_in_millis":0,"scroll_current":0},"merges":{"current":0,"current_docs":0,"current_size_in_bytes":0,"total":0,"total_time_in_millis":0,"total_docs":0,"total_size_in_bytes":0,"total_stopped_time_in_millis":0,"total_throttled_time_in_millis":0,"total_auto_throttle_in_bytes":104857600},"refresh":{"total":1,"total_time_in_millis":116},"flush":{"total":0,"total_time_in_millis":0},"warmer":{"current":0,"total":12,"total_time_in_millis":13},"query_cache":{"memory_size_in_bytes":0,"total_count":0,"hit_count":0,"miss_count":0,"cache_size":0,"cache_count":0,"evictions":0},"fielddata":{"memory_size_in_bytes":0,"evictions":0},"percolate":{"total":0,"time_in_millis":0,"current":0,"memory_size_in_bytes":-1,"memory_size":"-1b","queries":0},"completion":{"size_in_bytes":0},"segments":{"count":1,"memory_in_bytes":2106,"terms_memory_in_bytes":1510,"stored_fields_memory_in_bytes":312,"term_vectors_memory_in_bytes":0,"norms_memory_in_bytes":192,"doc_values_memory_in_bytes":92,"index_writer_memory_in_bytes":0,"index_writer_max_memory_in_bytes":34598635,"version_map_memory_in_bytes":0,"fixed_bit_set_memory_in_bytes":0},"translog":{"operations":1,"size_in_bytes":294},"suggest":{"total":0,"time_in_millis":0,"current":0},"request_cache":{"memory_size_in_bytes":0,"evictions":0,"hit_count":0,"miss_count":0},"recovery":{"current_as_source":0,"current_as_target":0,"throttle_time_in_millis":0}}},"foo_3":{"primaries":{"docs":{"count":1,"deleted":0},"store":{"size_in_bytes":3733,"throttle_time_in_millis":0},"indexing":{"index_total":1,"index_time_in_millis":1,"index_current":0,"index_failed":0,"delete_total":0,"delete_time_in_millis":0,"delete_current":0,"noop_update_total":0,"is_throttled":false,"throttle_time_in_millis":0},"get":{"total":0,"time_in_millis":0,"exists_total":0,"exists_time_in_millis":0,"missing_total":0,"missing_time_in_millis":0,"current":0},"search":{"open_contexts":0,"query_total":0,"query_time_in_millis":0,"query_current":0,"fetch_total":0,"fetch_time_in_millis":0,"fetch_current":0,"scroll_total":0,"scroll_time_in_millis":0,"scroll_current":0},"merges":{"current":0,"current_docs":0,"current_size_in_bytes":0,"total":0,"total_time_in_millis":0,"total_docs":0,"total_size_in_bytes":0,"total_stopped_time_in_millis":0,"total_throttled_time_in_millis":0,"total_auto_throttle_in_bytes":104857600},"refresh":{"total":1,"total_time_in_millis":16},"flush":{"total":0,"total_time_in_millis":0},"warmer":{"current":0,"total":12,"total_time_in_millis":0},"query_cache":{"memory_size_in_bytes":0,"total_count":0,"hit_count":0,"miss_count":0,"cache_size":0,"cache_count":0,"evictions":0},"fielddata":{"memory_size_in_bytes":0,"evictions":0},"percolate":{"total":0,"time_in_millis":0,"current":0,"memory_size_in_bytes":-1,"memory_size":"-1b","queries":0},"completion":{"size_in_bytes":0},"segments":{"count":1,"memory_in_bytes":2106,"terms_memory_in_bytes":1510,"stored_fields_memory_in_bytes":312,"term_vectors_memory_in_bytes":0,"norms_memory_in_bytes":192,"doc_values_memory_in_bytes":92,"index_writer_memory_in_bytes":0,"index_writer_max_memory_in_bytes":34598635,"version_map_memory_in_bytes":0,"fixed_bit_set_memory_in_bytes":0},"translog":{"operations":1,"size_in_bytes":300},"suggest":{"total":0,"time_in_millis":0,"current":0},"request_cache":{"memory_size_in_bytes":0,"evictions":0,"hit_count":0,"miss_count":0},"recovery":{"current_as_source":0,"current_as_target":0,"throttle_time_in_millis":0}},"total":{"docs":{"count":1,"deleted":0},"store":{"size_in_bytes":3733,"throttle_time_in_millis":0},"indexing":{"index_total":1,"index_time_in_millis":1,"index_current":0,"index_failed":0,"delete_total":0,"delete_time_in_millis":0,"delete_current":0,"noop_update_total":0,"is_throttled":false,"throttle_time_in_millis":0},"get":{"total":0,"time_in_millis":0,"exists_total":0,"exists_time_in_millis":0,"missing_total":0,"missing_time_in_millis":0,"current":0},"search":{"open_contexts":0,"query_total":0,"query_time_in_millis":0,"query_current":0,"fetch_total":0,"fetch_time_in_millis":0,"fetch_current":0,"scroll_total":0,"scroll_time_in_millis":0,"scroll_current":0},"merges":{"current":0,"current_docs":0,"current_size_in_bytes":0,"total":0,"total_time_in_millis":0,"total_docs":0,"total_size_in_bytes":0,"total_stopped_time_in_millis":0,"total_throttled_time_in_millis":0,"total_auto_throttle_in_bytes":104857600},"refresh":{"total":1,"total_time_in_millis":16},"flush":{"total":0,"total_time_in_millis":0},"warmer":{"current":0,"total":12,"total_time_in_millis":0},"query_cache":{"memory_size_in_bytes":0,"total_count":0,"hit_count":0,"miss_count":0,"cache_size":0,"cache_count":0,"evictions":0},"fielddata":{"memory_size_in_bytes":0,"evictions":0},"percolate":{"total":0,"time_in_millis":0,"current":0,"memory_size_in_bytes":-1,"memory_size":"-1b","queries":0},"completion":{"size_in_bytes":0},"segments":{"count":1,"memory_in_bytes":2106,"terms_memory_in_bytes":1510,"stored_fields_memory_in_bytes":312,"term_vectors_memory_in_bytes":0,"norms_memory_in_bytes":192,"doc_values_memory_in_bytes":92,"index_writer_memory_in_bytes":0,"index_writer_max_memory_in_bytes":34598635,"version_map_memory_in_bytes":0,"fixed_bit_set_memory_in_bytes":0},"translog":{"operations":1,"size_in_bytes":300},"suggest":{"total":0,"time_in_millis":0,"current":0},"request_cache":{"memory_size_in_bytes":0,"evictions":0,"hit_count":0,"miss_count":0},"recovery":{"current_as_source":0,"current_as_target":0,"throttle_time_in_millis":0}}}}}`, + }, + "5.4.2": { + "alias": `{"foo_1":{"aliases":{}},"foo_2":{"aliases":{"foo_alias_2_1":{}}},"foo_3":{"aliases":{"foo_alias_3_1":{"index_routing":"title","search_routing":"title","is_write_index":true},"foo_alias_3_2":{}}}}`, + "stats": `{"_shards":{"total":30,"successful":15,"failed":0},"_all":{"primaries":{"docs":{"count":3,"deleted":0},"store":{"size_in_bytes":13165,"throttle_time_in_millis":0},"indexing":{"index_total":3,"index_time_in_millis":80,"index_current":0,"index_failed":0,"delete_total":0,"delete_time_in_millis":0,"delete_current":0,"noop_update_total":0,"is_throttled":false,"throttle_time_in_millis":0},"get":{"total":0,"time_in_millis":0,"exists_total":0,"exists_time_in_millis":0,"missing_total":0,"missing_time_in_millis":0,"current":0},"search":{"open_contexts":0,"query_total":0,"query_time_in_millis":0,"query_current":0,"fetch_total":0,"fetch_time_in_millis":0,"fetch_current":0,"scroll_total":0,"scroll_time_in_millis":0,"scroll_current":0,"suggest_total":0,"suggest_time_in_millis":0,"suggest_current":0},"merges":{"current":0,"current_docs":0,"current_size_in_bytes":0,"total":0,"total_time_in_millis":0,"total_docs":0,"total_size_in_bytes":0,"total_stopped_time_in_millis":0,"total_throttled_time_in_millis":0,"total_auto_throttle_in_bytes":314572800},"refresh":{"total":3,"total_time_in_millis":1317,"listeners":0},"flush":{"total":0,"total_time_in_millis":0},"warmer":{"current":0,"total":18,"total_time_in_millis":26},"query_cache":{"memory_size_in_bytes":0,"total_count":0,"hit_count":0,"miss_count":0,"cache_size":0,"cache_count":0,"evictions":0},"fielddata":{"memory_size_in_bytes":0,"evictions":0},"completion":{"size_in_bytes":0},"segments":{"count":3,"memory_in_bytes":7764,"terms_memory_in_bytes":5976,"stored_fields_memory_in_bytes":936,"term_vectors_memory_in_bytes":0,"norms_memory_in_bytes":576,"points_memory_in_bytes":0,"doc_values_memory_in_bytes":276,"index_writer_memory_in_bytes":0,"version_map_memory_in_bytes":0,"fixed_bit_set_memory_in_bytes":0,"max_unsafe_auto_id_timestamp":-1,"file_sizes":{}},"translog":{"operations":3,"size_in_bytes":918},"request_cache":{"memory_size_in_bytes":0,"evictions":0,"hit_count":0,"miss_count":0},"recovery":{"current_as_source":0,"current_as_target":0,"throttle_time_in_millis":0}},"total":{"docs":{"count":3,"deleted":0},"store":{"size_in_bytes":13165,"throttle_time_in_millis":0},"indexing":{"index_total":3,"index_time_in_millis":80,"index_current":0,"index_failed":0,"delete_total":0,"delete_time_in_millis":0,"delete_current":0,"noop_update_total":0,"is_throttled":false,"throttle_time_in_millis":0},"get":{"total":0,"time_in_millis":0,"exists_total":0,"exists_time_in_millis":0,"missing_total":0,"missing_time_in_millis":0,"current":0},"search":{"open_contexts":0,"query_total":0,"query_time_in_millis":0,"query_current":0,"fetch_total":0,"fetch_time_in_millis":0,"fetch_current":0,"scroll_total":0,"scroll_time_in_millis":0,"scroll_current":0,"suggest_total":0,"suggest_time_in_millis":0,"suggest_current":0},"merges":{"current":0,"current_docs":0,"current_size_in_bytes":0,"total":0,"total_time_in_millis":0,"total_docs":0,"total_size_in_bytes":0,"total_stopped_time_in_millis":0,"total_throttled_time_in_millis":0,"total_auto_throttle_in_bytes":314572800},"refresh":{"total":3,"total_time_in_millis":1317,"listeners":0},"flush":{"total":0,"total_time_in_millis":0},"warmer":{"current":0,"total":18,"total_time_in_millis":26},"query_cache":{"memory_size_in_bytes":0,"total_count":0,"hit_count":0,"miss_count":0,"cache_size":0,"cache_count":0,"evictions":0},"fielddata":{"memory_size_in_bytes":0,"evictions":0},"completion":{"size_in_bytes":0},"segments":{"count":3,"memory_in_bytes":7764,"terms_memory_in_bytes":5976,"stored_fields_memory_in_bytes":936,"term_vectors_memory_in_bytes":0,"norms_memory_in_bytes":576,"points_memory_in_bytes":0,"doc_values_memory_in_bytes":276,"index_writer_memory_in_bytes":0,"version_map_memory_in_bytes":0,"fixed_bit_set_memory_in_bytes":0,"max_unsafe_auto_id_timestamp":-1,"file_sizes":{}},"translog":{"operations":3,"size_in_bytes":918},"request_cache":{"memory_size_in_bytes":0,"evictions":0,"hit_count":0,"miss_count":0},"recovery":{"current_as_source":0,"current_as_target":0,"throttle_time_in_millis":0}}},"indices":{"foo_2":{"primaries":{"docs":{"count":1,"deleted":0},"store":{"size_in_bytes":4408,"throttle_time_in_millis":0},"indexing":{"index_total":1,"index_time_in_millis":4,"index_current":0,"index_failed":0,"delete_total":0,"delete_time_in_millis":0,"delete_current":0,"noop_update_total":0,"is_throttled":false,"throttle_time_in_millis":0},"get":{"total":0,"time_in_millis":0,"exists_total":0,"exists_time_in_millis":0,"missing_total":0,"missing_time_in_millis":0,"current":0},"search":{"open_contexts":0,"query_total":0,"query_time_in_millis":0,"query_current":0,"fetch_total":0,"fetch_time_in_millis":0,"fetch_current":0,"scroll_total":0,"scroll_time_in_millis":0,"scroll_current":0,"suggest_total":0,"suggest_time_in_millis":0,"suggest_current":0},"merges":{"current":0,"current_docs":0,"current_size_in_bytes":0,"total":0,"total_time_in_millis":0,"total_docs":0,"total_size_in_bytes":0,"total_stopped_time_in_millis":0,"total_throttled_time_in_millis":0,"total_auto_throttle_in_bytes":104857600},"refresh":{"total":1,"total_time_in_millis":24,"listeners":0},"flush":{"total":0,"total_time_in_millis":0},"warmer":{"current":0,"total":6,"total_time_in_millis":0},"query_cache":{"memory_size_in_bytes":0,"total_count":0,"hit_count":0,"miss_count":0,"cache_size":0,"cache_count":0,"evictions":0},"fielddata":{"memory_size_in_bytes":0,"evictions":0},"completion":{"size_in_bytes":0},"segments":{"count":1,"memory_in_bytes":2588,"terms_memory_in_bytes":1992,"stored_fields_memory_in_bytes":312,"term_vectors_memory_in_bytes":0,"norms_memory_in_bytes":192,"points_memory_in_bytes":0,"doc_values_memory_in_bytes":92,"index_writer_memory_in_bytes":0,"version_map_memory_in_bytes":0,"fixed_bit_set_memory_in_bytes":0,"max_unsafe_auto_id_timestamp":-1,"file_sizes":{}},"translog":{"operations":1,"size_in_bytes":308},"request_cache":{"memory_size_in_bytes":0,"evictions":0,"hit_count":0,"miss_count":0},"recovery":{"current_as_source":0,"current_as_target":0,"throttle_time_in_millis":0}},"total":{"docs":{"count":1,"deleted":0},"store":{"size_in_bytes":4408,"throttle_time_in_millis":0},"indexing":{"index_total":1,"index_time_in_millis":4,"index_current":0,"index_failed":0,"delete_total":0,"delete_time_in_millis":0,"delete_current":0,"noop_update_total":0,"is_throttled":false,"throttle_time_in_millis":0},"get":{"total":0,"time_in_millis":0,"exists_total":0,"exists_time_in_millis":0,"missing_total":0,"missing_time_in_millis":0,"current":0},"search":{"open_contexts":0,"query_total":0,"query_time_in_millis":0,"query_current":0,"fetch_total":0,"fetch_time_in_millis":0,"fetch_current":0,"scroll_total":0,"scroll_time_in_millis":0,"scroll_current":0,"suggest_total":0,"suggest_time_in_millis":0,"suggest_current":0},"merges":{"current":0,"current_docs":0,"current_size_in_bytes":0,"total":0,"total_time_in_millis":0,"total_docs":0,"total_size_in_bytes":0,"total_stopped_time_in_millis":0,"total_throttled_time_in_millis":0,"total_auto_throttle_in_bytes":104857600},"refresh":{"total":1,"total_time_in_millis":24,"listeners":0},"flush":{"total":0,"total_time_in_millis":0},"warmer":{"current":0,"total":6,"total_time_in_millis":0},"query_cache":{"memory_size_in_bytes":0,"total_count":0,"hit_count":0,"miss_count":0,"cache_size":0,"cache_count":0,"evictions":0},"fielddata":{"memory_size_in_bytes":0,"evictions":0},"completion":{"size_in_bytes":0},"segments":{"count":1,"memory_in_bytes":2588,"terms_memory_in_bytes":1992,"stored_fields_memory_in_bytes":312,"term_vectors_memory_in_bytes":0,"norms_memory_in_bytes":192,"points_memory_in_bytes":0,"doc_values_memory_in_bytes":92,"index_writer_memory_in_bytes":0,"version_map_memory_in_bytes":0,"fixed_bit_set_memory_in_bytes":0,"max_unsafe_auto_id_timestamp":-1,"file_sizes":{}},"translog":{"operations":1,"size_in_bytes":308},"request_cache":{"memory_size_in_bytes":0,"evictions":0,"hit_count":0,"miss_count":0},"recovery":{"current_as_source":0,"current_as_target":0,"throttle_time_in_millis":0}}},"foo_1":{"primaries":{"docs":{"count":1,"deleted":0},"store":{"size_in_bytes":4349,"throttle_time_in_millis":0},"indexing":{"index_total":1,"index_time_in_millis":3,"index_current":0,"index_failed":0,"delete_total":0,"delete_time_in_millis":0,"delete_current":0,"noop_update_total":0,"is_throttled":false,"throttle_time_in_millis":0},"get":{"total":0,"time_in_millis":0,"exists_total":0,"exists_time_in_millis":0,"missing_total":0,"missing_time_in_millis":0,"current":0},"search":{"open_contexts":0,"query_total":0,"query_time_in_millis":0,"query_current":0,"fetch_total":0,"fetch_time_in_millis":0,"fetch_current":0,"scroll_total":0,"scroll_time_in_millis":0,"scroll_current":0,"suggest_total":0,"suggest_time_in_millis":0,"suggest_current":0},"merges":{"current":0,"current_docs":0,"current_size_in_bytes":0,"total":0,"total_time_in_millis":0,"total_docs":0,"total_size_in_bytes":0,"total_stopped_time_in_millis":0,"total_throttled_time_in_millis":0,"total_auto_throttle_in_bytes":104857600},"refresh":{"total":1,"total_time_in_millis":1166,"listeners":0},"flush":{"total":0,"total_time_in_millis":0},"warmer":{"current":0,"total":6,"total_time_in_millis":6},"query_cache":{"memory_size_in_bytes":0,"total_count":0,"hit_count":0,"miss_count":0,"cache_size":0,"cache_count":0,"evictions":0},"fielddata":{"memory_size_in_bytes":0,"evictions":0},"completion":{"size_in_bytes":0},"segments":{"count":1,"memory_in_bytes":2588,"terms_memory_in_bytes":1992,"stored_fields_memory_in_bytes":312,"term_vectors_memory_in_bytes":0,"norms_memory_in_bytes":192,"points_memory_in_bytes":0,"doc_values_memory_in_bytes":92,"index_writer_memory_in_bytes":0,"version_map_memory_in_bytes":0,"fixed_bit_set_memory_in_bytes":0,"max_unsafe_auto_id_timestamp":-1,"file_sizes":{}},"translog":{"operations":1,"size_in_bytes":302},"request_cache":{"memory_size_in_bytes":0,"evictions":0,"hit_count":0,"miss_count":0},"recovery":{"current_as_source":0,"current_as_target":0,"throttle_time_in_millis":0}},"total":{"docs":{"count":1,"deleted":0},"store":{"size_in_bytes":4349,"throttle_time_in_millis":0},"indexing":{"index_total":1,"index_time_in_millis":3,"index_current":0,"index_failed":0,"delete_total":0,"delete_time_in_millis":0,"delete_current":0,"noop_update_total":0,"is_throttled":false,"throttle_time_in_millis":0},"get":{"total":0,"time_in_millis":0,"exists_total":0,"exists_time_in_millis":0,"missing_total":0,"missing_time_in_millis":0,"current":0},"search":{"open_contexts":0,"query_total":0,"query_time_in_millis":0,"query_current":0,"fetch_total":0,"fetch_time_in_millis":0,"fetch_current":0,"scroll_total":0,"scroll_time_in_millis":0,"scroll_current":0,"suggest_total":0,"suggest_time_in_millis":0,"suggest_current":0},"merges":{"current":0,"current_docs":0,"current_size_in_bytes":0,"total":0,"total_time_in_millis":0,"total_docs":0,"total_size_in_bytes":0,"total_stopped_time_in_millis":0,"total_throttled_time_in_millis":0,"total_auto_throttle_in_bytes":104857600},"refresh":{"total":1,"total_time_in_millis":1166,"listeners":0},"flush":{"total":0,"total_time_in_millis":0},"warmer":{"current":0,"total":6,"total_time_in_millis":6},"query_cache":{"memory_size_in_bytes":0,"total_count":0,"hit_count":0,"miss_count":0,"cache_size":0,"cache_count":0,"evictions":0},"fielddata":{"memory_size_in_bytes":0,"evictions":0},"completion":{"size_in_bytes":0},"segments":{"count":1,"memory_in_bytes":2588,"terms_memory_in_bytes":1992,"stored_fields_memory_in_bytes":312,"term_vectors_memory_in_bytes":0,"norms_memory_in_bytes":192,"points_memory_in_bytes":0,"doc_values_memory_in_bytes":92,"index_writer_memory_in_bytes":0,"version_map_memory_in_bytes":0,"fixed_bit_set_memory_in_bytes":0,"max_unsafe_auto_id_timestamp":-1,"file_sizes":{}},"translog":{"operations":1,"size_in_bytes":302},"request_cache":{"memory_size_in_bytes":0,"evictions":0,"hit_count":0,"miss_count":0},"recovery":{"current_as_source":0,"current_as_target":0,"throttle_time_in_millis":0}}},"foo_3":{"primaries":{"docs":{"count":1,"deleted":0},"store":{"size_in_bytes":4408,"throttle_time_in_millis":0},"indexing":{"index_total":1,"index_time_in_millis":73,"index_current":0,"index_failed":0,"delete_total":0,"delete_time_in_millis":0,"delete_current":0,"noop_update_total":0,"is_throttled":false,"throttle_time_in_millis":0},"get":{"total":0,"time_in_millis":0,"exists_total":0,"exists_time_in_millis":0,"missing_total":0,"missing_time_in_millis":0,"current":0},"search":{"open_contexts":0,"query_total":0,"query_time_in_millis":0,"query_current":0,"fetch_total":0,"fetch_time_in_millis":0,"fetch_current":0,"scroll_total":0,"scroll_time_in_millis":0,"scroll_current":0,"suggest_total":0,"suggest_time_in_millis":0,"suggest_current":0},"merges":{"current":0,"current_docs":0,"current_size_in_bytes":0,"total":0,"total_time_in_millis":0,"total_docs":0,"total_size_in_bytes":0,"total_stopped_time_in_millis":0,"total_throttled_time_in_millis":0,"total_auto_throttle_in_bytes":104857600},"refresh":{"total":1,"total_time_in_millis":127,"listeners":0},"flush":{"total":0,"total_time_in_millis":0},"warmer":{"current":0,"total":6,"total_time_in_millis":20},"query_cache":{"memory_size_in_bytes":0,"total_count":0,"hit_count":0,"miss_count":0,"cache_size":0,"cache_count":0,"evictions":0},"fielddata":{"memory_size_in_bytes":0,"evictions":0},"completion":{"size_in_bytes":0},"segments":{"count":1,"memory_in_bytes":2588,"terms_memory_in_bytes":1992,"stored_fields_memory_in_bytes":312,"term_vectors_memory_in_bytes":0,"norms_memory_in_bytes":192,"points_memory_in_bytes":0,"doc_values_memory_in_bytes":92,"index_writer_memory_in_bytes":0,"version_map_memory_in_bytes":0,"fixed_bit_set_memory_in_bytes":0,"max_unsafe_auto_id_timestamp":-1,"file_sizes":{}},"translog":{"operations":1,"size_in_bytes":308},"request_cache":{"memory_size_in_bytes":0,"evictions":0,"hit_count":0,"miss_count":0},"recovery":{"current_as_source":0,"current_as_target":0,"throttle_time_in_millis":0}},"total":{"docs":{"count":1,"deleted":0},"store":{"size_in_bytes":4408,"throttle_time_in_millis":0},"indexing":{"index_total":1,"index_time_in_millis":73,"index_current":0,"index_failed":0,"delete_total":0,"delete_time_in_millis":0,"delete_current":0,"noop_update_total":0,"is_throttled":false,"throttle_time_in_millis":0},"get":{"total":0,"time_in_millis":0,"exists_total":0,"exists_time_in_millis":0,"missing_total":0,"missing_time_in_millis":0,"current":0},"search":{"open_contexts":0,"query_total":0,"query_time_in_millis":0,"query_current":0,"fetch_total":0,"fetch_time_in_millis":0,"fetch_current":0,"scroll_total":0,"scroll_time_in_millis":0,"scroll_current":0,"suggest_total":0,"suggest_time_in_millis":0,"suggest_current":0},"merges":{"current":0,"current_docs":0,"current_size_in_bytes":0,"total":0,"total_time_in_millis":0,"total_docs":0,"total_size_in_bytes":0,"total_stopped_time_in_millis":0,"total_throttled_time_in_millis":0,"total_auto_throttle_in_bytes":104857600},"refresh":{"total":1,"total_time_in_millis":127,"listeners":0},"flush":{"total":0,"total_time_in_millis":0},"warmer":{"current":0,"total":6,"total_time_in_millis":20},"query_cache":{"memory_size_in_bytes":0,"total_count":0,"hit_count":0,"miss_count":0,"cache_size":0,"cache_count":0,"evictions":0},"fielddata":{"memory_size_in_bytes":0,"evictions":0},"completion":{"size_in_bytes":0},"segments":{"count":1,"memory_in_bytes":2588,"terms_memory_in_bytes":1992,"stored_fields_memory_in_bytes":312,"term_vectors_memory_in_bytes":0,"norms_memory_in_bytes":192,"points_memory_in_bytes":0,"doc_values_memory_in_bytes":92,"index_writer_memory_in_bytes":0,"version_map_memory_in_bytes":0,"fixed_bit_set_memory_in_bytes":0,"max_unsafe_auto_id_timestamp":-1,"file_sizes":{}},"translog":{"operations":1,"size_in_bytes":308},"request_cache":{"memory_size_in_bytes":0,"evictions":0,"hit_count":0,"miss_count":0},"recovery":{"current_as_source":0,"current_as_target":0,"throttle_time_in_millis":0}}}}}`, + }, + "7.17.3": { + "alias": `{"foo_1":{"aliases":{}},"foo_2":{"aliases":{"foo_alias_2_1":{}}},"foo_3":{"aliases":{"foo_alias_3_1":{"index_routing":"title","search_routing":"title","is_write_index":true},"foo_alias_3_2":{}}}}`, + "stats": `{"_shards":{"total":7,"successful":4,"failed":0},"_all":{"primaries":{"docs":{"count":43,"deleted":0},"shard_stats":{"total_count":4},"store":{"size_in_bytes":39917364,"total_data_set_size_in_bytes":39917364,"reserved_in_bytes":0},"indexing":{"index_total":43,"index_time_in_millis":741,"index_current":0,"index_failed":0,"delete_total":0,"delete_time_in_millis":0,"delete_current":0,"noop_update_total":0,"is_throttled":false,"throttle_time_in_millis":0},"get":{"total":0,"time_in_millis":0,"exists_total":0,"exists_time_in_millis":0,"missing_total":0,"missing_time_in_millis":0,"current":0},"search":{"open_contexts":0,"query_total":43,"query_time_in_millis":71,"query_current":0,"fetch_total":43,"fetch_time_in_millis":96,"fetch_current":0,"scroll_total":3,"scroll_time_in_millis":60,"scroll_current":0,"suggest_total":0,"suggest_time_in_millis":0,"suggest_current":0},"merges":{"current":0,"current_docs":0,"current_size_in_bytes":0,"total":0,"total_time_in_millis":0,"total_docs":0,"total_size_in_bytes":0,"total_stopped_time_in_millis":0,"total_throttled_time_in_millis":0,"total_auto_throttle_in_bytes":83886080},"refresh":{"total":18,"total_time_in_millis":76,"external_total":15,"external_total_time_in_millis":73,"listeners":0},"flush":{"total":4,"periodic":0,"total_time_in_millis":150},"warmer":{"current":0,"total":11,"total_time_in_millis":0},"query_cache":{"memory_size_in_bytes":0,"total_count":0,"hit_count":0,"miss_count":0,"cache_size":0,"cache_count":0,"evictions":0},"fielddata":{"memory_size_in_bytes":0,"evictions":0},"completion":{"size_in_bytes":0},"segments":{"count":7,"memory_in_bytes":9996,"terms_memory_in_bytes":5600,"stored_fields_memory_in_bytes":3480,"term_vectors_memory_in_bytes":0,"norms_memory_in_bytes":384,"points_memory_in_bytes":0,"doc_values_memory_in_bytes":532,"index_writer_memory_in_bytes":0,"version_map_memory_in_bytes":0,"fixed_bit_set_memory_in_bytes":0,"max_unsafe_auto_id_timestamp":-1,"file_sizes":{}},"translog":{"operations":3,"size_in_bytes":487,"uncommitted_operations":3,"uncommitted_size_in_bytes":487,"earliest_last_modified_age":35855},"request_cache":{"memory_size_in_bytes":0,"evictions":0,"hit_count":0,"miss_count":0},"recovery":{"current_as_source":0,"current_as_target":0,"throttle_time_in_millis":0}},"total":{"docs":{"count":43,"deleted":0},"shard_stats":{"total_count":4},"store":{"size_in_bytes":39917364,"total_data_set_size_in_bytes":39917364,"reserved_in_bytes":0},"indexing":{"index_total":43,"index_time_in_millis":741,"index_current":0,"index_failed":0,"delete_total":0,"delete_time_in_millis":0,"delete_current":0,"noop_update_total":0,"is_throttled":false,"throttle_time_in_millis":0},"get":{"total":0,"time_in_millis":0,"exists_total":0,"exists_time_in_millis":0,"missing_total":0,"missing_time_in_millis":0,"current":0},"search":{"open_contexts":0,"query_total":43,"query_time_in_millis":71,"query_current":0,"fetch_total":43,"fetch_time_in_millis":96,"fetch_current":0,"scroll_total":3,"scroll_time_in_millis":60,"scroll_current":0,"suggest_total":0,"suggest_time_in_millis":0,"suggest_current":0},"merges":{"current":0,"current_docs":0,"current_size_in_bytes":0,"total":0,"total_time_in_millis":0,"total_docs":0,"total_size_in_bytes":0,"total_stopped_time_in_millis":0,"total_throttled_time_in_millis":0,"total_auto_throttle_in_bytes":83886080},"refresh":{"total":18,"total_time_in_millis":76,"external_total":15,"external_total_time_in_millis":73,"listeners":0},"flush":{"total":4,"periodic":0,"total_time_in_millis":150},"warmer":{"current":0,"total":11,"total_time_in_millis":0},"query_cache":{"memory_size_in_bytes":0,"total_count":0,"hit_count":0,"miss_count":0,"cache_size":0,"cache_count":0,"evictions":0},"fielddata":{"memory_size_in_bytes":0,"evictions":0},"completion":{"size_in_bytes":0},"segments":{"count":7,"memory_in_bytes":9996,"terms_memory_in_bytes":5600,"stored_fields_memory_in_bytes":3480,"term_vectors_memory_in_bytes":0,"norms_memory_in_bytes":384,"points_memory_in_bytes":0,"doc_values_memory_in_bytes":532,"index_writer_memory_in_bytes":0,"version_map_memory_in_bytes":0,"fixed_bit_set_memory_in_bytes":0,"max_unsafe_auto_id_timestamp":-1,"file_sizes":{}},"translog":{"operations":3,"size_in_bytes":487,"uncommitted_operations":3,"uncommitted_size_in_bytes":487,"earliest_last_modified_age":35855},"request_cache":{"memory_size_in_bytes":0,"evictions":0,"hit_count":0,"miss_count":0},"recovery":{"current_as_source":0,"current_as_target":0,"throttle_time_in_millis":0}}},"indices":{".geoip_databases":{"uuid":"AbBfA8RRRLGfbIPGIAQs7A","primaries":{"docs":{"count":40,"deleted":0},"shard_stats":{"total_count":1},"store":{"size_in_bytes":39904033,"total_data_set_size_in_bytes":39904033,"reserved_in_bytes":0},"indexing":{"index_total":40,"index_time_in_millis":738,"index_current":0,"index_failed":0,"delete_total":0,"delete_time_in_millis":0,"delete_current":0,"noop_update_total":0,"is_throttled":false,"throttle_time_in_millis":0},"get":{"total":0,"time_in_millis":0,"exists_total":0,"exists_time_in_millis":0,"missing_total":0,"missing_time_in_millis":0,"current":0},"search":{"open_contexts":0,"query_total":43,"query_time_in_millis":71,"query_current":0,"fetch_total":43,"fetch_time_in_millis":96,"fetch_current":0,"scroll_total":3,"scroll_time_in_millis":60,"scroll_current":0,"suggest_total":0,"suggest_time_in_millis":0,"suggest_current":0},"merges":{"current":0,"current_docs":0,"current_size_in_bytes":0,"total":0,"total_time_in_millis":0,"total_docs":0,"total_size_in_bytes":0,"total_stopped_time_in_millis":0,"total_throttled_time_in_millis":0,"total_auto_throttle_in_bytes":20971520},"refresh":{"total":9,"total_time_in_millis":50,"external_total":6,"external_total_time_in_millis":45,"listeners":0},"flush":{"total":4,"periodic":0,"total_time_in_millis":150},"warmer":{"current":0,"total":5,"total_time_in_millis":0},"query_cache":{"memory_size_in_bytes":0,"total_count":0,"hit_count":0,"miss_count":0,"cache_size":0,"cache_count":0,"evictions":0},"fielddata":{"memory_size_in_bytes":0,"evictions":0},"completion":{"size_in_bytes":0},"segments":{"count":4,"memory_in_bytes":4368,"terms_memory_in_bytes":2048,"stored_fields_memory_in_bytes":2016,"term_vectors_memory_in_bytes":0,"norms_memory_in_bytes":0,"points_memory_in_bytes":0,"doc_values_memory_in_bytes":304,"index_writer_memory_in_bytes":0,"version_map_memory_in_bytes":0,"fixed_bit_set_memory_in_bytes":0,"max_unsafe_auto_id_timestamp":-1,"file_sizes":{}},"translog":{"operations":0,"size_in_bytes":55,"uncommitted_operations":0,"uncommitted_size_in_bytes":55,"earliest_last_modified_age":406186},"request_cache":{"memory_size_in_bytes":0,"evictions":0,"hit_count":0,"miss_count":0},"recovery":{"current_as_source":0,"current_as_target":0,"throttle_time_in_millis":0}},"total":{"docs":{"count":40,"deleted":0},"shard_stats":{"total_count":1},"store":{"size_in_bytes":39904033,"total_data_set_size_in_bytes":39904033,"reserved_in_bytes":0},"indexing":{"index_total":40,"index_time_in_millis":738,"index_current":0,"index_failed":0,"delete_total":0,"delete_time_in_millis":0,"delete_current":0,"noop_update_total":0,"is_throttled":false,"throttle_time_in_millis":0},"get":{"total":0,"time_in_millis":0,"exists_total":0,"exists_time_in_millis":0,"missing_total":0,"missing_time_in_millis":0,"current":0},"search":{"open_contexts":0,"query_total":43,"query_time_in_millis":71,"query_current":0,"fetch_total":43,"fetch_time_in_millis":96,"fetch_current":0,"scroll_total":3,"scroll_time_in_millis":60,"scroll_current":0,"suggest_total":0,"suggest_time_in_millis":0,"suggest_current":0},"merges":{"current":0,"current_docs":0,"current_size_in_bytes":0,"total":0,"total_time_in_millis":0,"total_docs":0,"total_size_in_bytes":0,"total_stopped_time_in_millis":0,"total_throttled_time_in_millis":0,"total_auto_throttle_in_bytes":20971520},"refresh":{"total":9,"total_time_in_millis":50,"external_total":6,"external_total_time_in_millis":45,"listeners":0},"flush":{"total":4,"periodic":0,"total_time_in_millis":150},"warmer":{"current":0,"total":5,"total_time_in_millis":0},"query_cache":{"memory_size_in_bytes":0,"total_count":0,"hit_count":0,"miss_count":0,"cache_size":0,"cache_count":0,"evictions":0},"fielddata":{"memory_size_in_bytes":0,"evictions":0},"completion":{"size_in_bytes":0},"segments":{"count":4,"memory_in_bytes":4368,"terms_memory_in_bytes":2048,"stored_fields_memory_in_bytes":2016,"term_vectors_memory_in_bytes":0,"norms_memory_in_bytes":0,"points_memory_in_bytes":0,"doc_values_memory_in_bytes":304,"index_writer_memory_in_bytes":0,"version_map_memory_in_bytes":0,"fixed_bit_set_memory_in_bytes":0,"max_unsafe_auto_id_timestamp":-1,"file_sizes":{}},"translog":{"operations":0,"size_in_bytes":55,"uncommitted_operations":0,"uncommitted_size_in_bytes":55,"earliest_last_modified_age":406186},"request_cache":{"memory_size_in_bytes":0,"evictions":0,"hit_count":0,"miss_count":0},"recovery":{"current_as_source":0,"current_as_target":0,"throttle_time_in_millis":0}}},"foo_2":{"uuid":"JnYmxu4DStKroXSy6BHYcQ","primaries":{"docs":{"count":1,"deleted":0},"shard_stats":{"total_count":1},"store":{"size_in_bytes":4459,"total_data_set_size_in_bytes":4459,"reserved_in_bytes":0},"indexing":{"index_total":1,"index_time_in_millis":1,"index_current":0,"index_failed":0,"delete_total":0,"delete_time_in_millis":0,"delete_current":0,"noop_update_total":0,"is_throttled":false,"throttle_time_in_millis":0},"get":{"total":0,"time_in_millis":0,"exists_total":0,"exists_time_in_millis":0,"missing_total":0,"missing_time_in_millis":0,"current":0},"search":{"open_contexts":0,"query_total":0,"query_time_in_millis":0,"query_current":0,"fetch_total":0,"fetch_time_in_millis":0,"fetch_current":0,"scroll_total":0,"scroll_time_in_millis":0,"scroll_current":0,"suggest_total":0,"suggest_time_in_millis":0,"suggest_current":0},"merges":{"current":0,"current_docs":0,"current_size_in_bytes":0,"total":0,"total_time_in_millis":0,"total_docs":0,"total_size_in_bytes":0,"total_stopped_time_in_millis":0,"total_throttled_time_in_millis":0,"total_auto_throttle_in_bytes":20971520},"refresh":{"total":3,"total_time_in_millis":9,"external_total":3,"external_total_time_in_millis":10,"listeners":0},"flush":{"total":0,"periodic":0,"total_time_in_millis":0},"warmer":{"current":0,"total":2,"total_time_in_millis":0},"query_cache":{"memory_size_in_bytes":0,"total_count":0,"hit_count":0,"miss_count":0,"cache_size":0,"cache_count":0,"evictions":0},"fielddata":{"memory_size_in_bytes":0,"evictions":0},"completion":{"size_in_bytes":0},"segments":{"count":1,"memory_in_bytes":1876,"terms_memory_in_bytes":1184,"stored_fields_memory_in_bytes":488,"term_vectors_memory_in_bytes":0,"norms_memory_in_bytes":128,"points_memory_in_bytes":0,"doc_values_memory_in_bytes":76,"index_writer_memory_in_bytes":0,"version_map_memory_in_bytes":0,"fixed_bit_set_memory_in_bytes":0,"max_unsafe_auto_id_timestamp":-1,"file_sizes":{}},"translog":{"operations":1,"size_in_bytes":146,"uncommitted_operations":1,"uncommitted_size_in_bytes":146,"earliest_last_modified_age":36079},"request_cache":{"memory_size_in_bytes":0,"evictions":0,"hit_count":0,"miss_count":0},"recovery":{"current_as_source":0,"current_as_target":0,"throttle_time_in_millis":0}},"total":{"docs":{"count":1,"deleted":0},"shard_stats":{"total_count":1},"store":{"size_in_bytes":4459,"total_data_set_size_in_bytes":4459,"reserved_in_bytes":0},"indexing":{"index_total":1,"index_time_in_millis":1,"index_current":0,"index_failed":0,"delete_total":0,"delete_time_in_millis":0,"delete_current":0,"noop_update_total":0,"is_throttled":false,"throttle_time_in_millis":0},"get":{"total":0,"time_in_millis":0,"exists_total":0,"exists_time_in_millis":0,"missing_total":0,"missing_time_in_millis":0,"current":0},"search":{"open_contexts":0,"query_total":0,"query_time_in_millis":0,"query_current":0,"fetch_total":0,"fetch_time_in_millis":0,"fetch_current":0,"scroll_total":0,"scroll_time_in_millis":0,"scroll_current":0,"suggest_total":0,"suggest_time_in_millis":0,"suggest_current":0},"merges":{"current":0,"current_docs":0,"current_size_in_bytes":0,"total":0,"total_time_in_millis":0,"total_docs":0,"total_size_in_bytes":0,"total_stopped_time_in_millis":0,"total_throttled_time_in_millis":0,"total_auto_throttle_in_bytes":20971520},"refresh":{"total":3,"total_time_in_millis":9,"external_total":3,"external_total_time_in_millis":10,"listeners":0},"flush":{"total":0,"periodic":0,"total_time_in_millis":0},"warmer":{"current":0,"total":2,"total_time_in_millis":0},"query_cache":{"memory_size_in_bytes":0,"total_count":0,"hit_count":0,"miss_count":0,"cache_size":0,"cache_count":0,"evictions":0},"fielddata":{"memory_size_in_bytes":0,"evictions":0},"completion":{"size_in_bytes":0},"segments":{"count":1,"memory_in_bytes":1876,"terms_memory_in_bytes":1184,"stored_fields_memory_in_bytes":488,"term_vectors_memory_in_bytes":0,"norms_memory_in_bytes":128,"points_memory_in_bytes":0,"doc_values_memory_in_bytes":76,"index_writer_memory_in_bytes":0,"version_map_memory_in_bytes":0,"fixed_bit_set_memory_in_bytes":0,"max_unsafe_auto_id_timestamp":-1,"file_sizes":{}},"translog":{"operations":1,"size_in_bytes":146,"uncommitted_operations":1,"uncommitted_size_in_bytes":146,"earliest_last_modified_age":36079},"request_cache":{"memory_size_in_bytes":0,"evictions":0,"hit_count":0,"miss_count":0},"recovery":{"current_as_source":0,"current_as_target":0,"throttle_time_in_millis":0}}},"foo_1":{"uuid":"9itiRXMuQym8eTdKygV3Kw","primaries":{"docs":{"count":1,"deleted":0},"shard_stats":{"total_count":1},"store":{"size_in_bytes":4413,"total_data_set_size_in_bytes":4413,"reserved_in_bytes":0},"indexing":{"index_total":1,"index_time_in_millis":1,"index_current":0,"index_failed":0,"delete_total":0,"delete_time_in_millis":0,"delete_current":0,"noop_update_total":0,"is_throttled":false,"throttle_time_in_millis":0},"get":{"total":0,"time_in_millis":0,"exists_total":0,"exists_time_in_millis":0,"missing_total":0,"missing_time_in_millis":0,"current":0},"search":{"open_contexts":0,"query_total":0,"query_time_in_millis":0,"query_current":0,"fetch_total":0,"fetch_time_in_millis":0,"fetch_current":0,"scroll_total":0,"scroll_time_in_millis":0,"scroll_current":0,"suggest_total":0,"suggest_time_in_millis":0,"suggest_current":0},"merges":{"current":0,"current_docs":0,"current_size_in_bytes":0,"total":0,"total_time_in_millis":0,"total_docs":0,"total_size_in_bytes":0,"total_stopped_time_in_millis":0,"total_throttled_time_in_millis":0,"total_auto_throttle_in_bytes":20971520},"refresh":{"total":3,"total_time_in_millis":8,"external_total":3,"external_total_time_in_millis":8,"listeners":0},"flush":{"total":0,"periodic":0,"total_time_in_millis":0},"warmer":{"current":0,"total":2,"total_time_in_millis":0},"query_cache":{"memory_size_in_bytes":0,"total_count":0,"hit_count":0,"miss_count":0,"cache_size":0,"cache_count":0,"evictions":0},"fielddata":{"memory_size_in_bytes":0,"evictions":0},"completion":{"size_in_bytes":0},"segments":{"count":1,"memory_in_bytes":1876,"terms_memory_in_bytes":1184,"stored_fields_memory_in_bytes":488,"term_vectors_memory_in_bytes":0,"norms_memory_in_bytes":128,"points_memory_in_bytes":0,"doc_values_memory_in_bytes":76,"index_writer_memory_in_bytes":0,"version_map_memory_in_bytes":0,"fixed_bit_set_memory_in_bytes":0,"max_unsafe_auto_id_timestamp":-1,"file_sizes":{}},"translog":{"operations":1,"size_in_bytes":140,"uncommitted_operations":1,"uncommitted_size_in_bytes":140,"earliest_last_modified_age":36364},"request_cache":{"memory_size_in_bytes":0,"evictions":0,"hit_count":0,"miss_count":0},"recovery":{"current_as_source":0,"current_as_target":0,"throttle_time_in_millis":0}},"total":{"docs":{"count":1,"deleted":0},"shard_stats":{"total_count":1},"store":{"size_in_bytes":4413,"total_data_set_size_in_bytes":4413,"reserved_in_bytes":0},"indexing":{"index_total":1,"index_time_in_millis":1,"index_current":0,"index_failed":0,"delete_total":0,"delete_time_in_millis":0,"delete_current":0,"noop_update_total":0,"is_throttled":false,"throttle_time_in_millis":0},"get":{"total":0,"time_in_millis":0,"exists_total":0,"exists_time_in_millis":0,"missing_total":0,"missing_time_in_millis":0,"current":0},"search":{"open_contexts":0,"query_total":0,"query_time_in_millis":0,"query_current":0,"fetch_total":0,"fetch_time_in_millis":0,"fetch_current":0,"scroll_total":0,"scroll_time_in_millis":0,"scroll_current":0,"suggest_total":0,"suggest_time_in_millis":0,"suggest_current":0},"merges":{"current":0,"current_docs":0,"current_size_in_bytes":0,"total":0,"total_time_in_millis":0,"total_docs":0,"total_size_in_bytes":0,"total_stopped_time_in_millis":0,"total_throttled_time_in_millis":0,"total_auto_throttle_in_bytes":20971520},"refresh":{"total":3,"total_time_in_millis":8,"external_total":3,"external_total_time_in_millis":8,"listeners":0},"flush":{"total":0,"periodic":0,"total_time_in_millis":0},"warmer":{"current":0,"total":2,"total_time_in_millis":0},"query_cache":{"memory_size_in_bytes":0,"total_count":0,"hit_count":0,"miss_count":0,"cache_size":0,"cache_count":0,"evictions":0},"fielddata":{"memory_size_in_bytes":0,"evictions":0},"completion":{"size_in_bytes":0},"segments":{"count":1,"memory_in_bytes":1876,"terms_memory_in_bytes":1184,"stored_fields_memory_in_bytes":488,"term_vectors_memory_in_bytes":0,"norms_memory_in_bytes":128,"points_memory_in_bytes":0,"doc_values_memory_in_bytes":76,"index_writer_memory_in_bytes":0,"version_map_memory_in_bytes":0,"fixed_bit_set_memory_in_bytes":0,"max_unsafe_auto_id_timestamp":-1,"file_sizes":{}},"translog":{"operations":1,"size_in_bytes":140,"uncommitted_operations":1,"uncommitted_size_in_bytes":140,"earliest_last_modified_age":36364},"request_cache":{"memory_size_in_bytes":0,"evictions":0,"hit_count":0,"miss_count":0},"recovery":{"current_as_source":0,"current_as_target":0,"throttle_time_in_millis":0}}},"foo_3":{"uuid":"a2-lU19tRuKUPgarKpqoCg","primaries":{"docs":{"count":1,"deleted":0},"shard_stats":{"total_count":1},"store":{"size_in_bytes":4459,"total_data_set_size_in_bytes":4459,"reserved_in_bytes":0},"indexing":{"index_total":1,"index_time_in_millis":1,"index_current":0,"index_failed":0,"delete_total":0,"delete_time_in_millis":0,"delete_current":0,"noop_update_total":0,"is_throttled":false,"throttle_time_in_millis":0},"get":{"total":0,"time_in_millis":0,"exists_total":0,"exists_time_in_millis":0,"missing_total":0,"missing_time_in_millis":0,"current":0},"search":{"open_contexts":0,"query_total":0,"query_time_in_millis":0,"query_current":0,"fetch_total":0,"fetch_time_in_millis":0,"fetch_current":0,"scroll_total":0,"scroll_time_in_millis":0,"scroll_current":0,"suggest_total":0,"suggest_time_in_millis":0,"suggest_current":0},"merges":{"current":0,"current_docs":0,"current_size_in_bytes":0,"total":0,"total_time_in_millis":0,"total_docs":0,"total_size_in_bytes":0,"total_stopped_time_in_millis":0,"total_throttled_time_in_millis":0,"total_auto_throttle_in_bytes":20971520},"refresh":{"total":3,"total_time_in_millis":9,"external_total":3,"external_total_time_in_millis":10,"listeners":0},"flush":{"total":0,"periodic":0,"total_time_in_millis":0},"warmer":{"current":0,"total":2,"total_time_in_millis":0},"query_cache":{"memory_size_in_bytes":0,"total_count":0,"hit_count":0,"miss_count":0,"cache_size":0,"cache_count":0,"evictions":0},"fielddata":{"memory_size_in_bytes":0,"evictions":0},"completion":{"size_in_bytes":0},"segments":{"count":1,"memory_in_bytes":1876,"terms_memory_in_bytes":1184,"stored_fields_memory_in_bytes":488,"term_vectors_memory_in_bytes":0,"norms_memory_in_bytes":128,"points_memory_in_bytes":0,"doc_values_memory_in_bytes":76,"index_writer_memory_in_bytes":0,"version_map_memory_in_bytes":0,"fixed_bit_set_memory_in_bytes":0,"max_unsafe_auto_id_timestamp":-1,"file_sizes":{}},"translog":{"operations":1,"size_in_bytes":146,"uncommitted_operations":1,"uncommitted_size_in_bytes":146,"earliest_last_modified_age":35855},"request_cache":{"memory_size_in_bytes":0,"evictions":0,"hit_count":0,"miss_count":0},"recovery":{"current_as_source":0,"current_as_target":0,"throttle_time_in_millis":0}},"total":{"docs":{"count":1,"deleted":0},"shard_stats":{"total_count":1},"store":{"size_in_bytes":4459,"total_data_set_size_in_bytes":4459,"reserved_in_bytes":0},"indexing":{"index_total":1,"index_time_in_millis":1,"index_current":0,"index_failed":0,"delete_total":0,"delete_time_in_millis":0,"delete_current":0,"noop_update_total":0,"is_throttled":false,"throttle_time_in_millis":0},"get":{"total":0,"time_in_millis":0,"exists_total":0,"exists_time_in_millis":0,"missing_total":0,"missing_time_in_millis":0,"current":0},"search":{"open_contexts":0,"query_total":0,"query_time_in_millis":0,"query_current":0,"fetch_total":0,"fetch_time_in_millis":0,"fetch_current":0,"scroll_total":0,"scroll_time_in_millis":0,"scroll_current":0,"suggest_total":0,"suggest_time_in_millis":0,"suggest_current":0},"merges":{"current":0,"current_docs":0,"current_size_in_bytes":0,"total":0,"total_time_in_millis":0,"total_docs":0,"total_size_in_bytes":0,"total_stopped_time_in_millis":0,"total_throttled_time_in_millis":0,"total_auto_throttle_in_bytes":20971520},"refresh":{"total":3,"total_time_in_millis":9,"external_total":3,"external_total_time_in_millis":10,"listeners":0},"flush":{"total":0,"periodic":0,"total_time_in_millis":0},"warmer":{"current":0,"total":2,"total_time_in_millis":0},"query_cache":{"memory_size_in_bytes":0,"total_count":0,"hit_count":0,"miss_count":0,"cache_size":0,"cache_count":0,"evictions":0},"fielddata":{"memory_size_in_bytes":0,"evictions":0},"completion":{"size_in_bytes":0},"segments":{"count":1,"memory_in_bytes":1876,"terms_memory_in_bytes":1184,"stored_fields_memory_in_bytes":488,"term_vectors_memory_in_bytes":0,"norms_memory_in_bytes":128,"points_memory_in_bytes":0,"doc_values_memory_in_bytes":76,"index_writer_memory_in_bytes":0,"version_map_memory_in_bytes":0,"fixed_bit_set_memory_in_bytes":0,"max_unsafe_auto_id_timestamp":-1,"file_sizes":{}},"translog":{"operations":1,"size_in_bytes":146,"uncommitted_operations":1,"uncommitted_size_in_bytes":146,"earliest_last_modified_age":35855},"request_cache":{"memory_size_in_bytes":0,"evictions":0,"hit_count":0,"miss_count":0},"recovery":{"current_as_source":0,"current_as_target":0,"throttle_time_in_millis":0}}}}}`, + }, + } + for ver, out := range ti { + mux := http.NewServeMux() + mux.HandleFunc("/_all/_stats", func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, out["stats"]) + }) + mux.HandleFunc("/_alias", func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, out["alias"]) + }) + ts := httptest.NewServer(mux) + defer ts.Close() + + u, err := url.Parse(ts.URL) + if err != nil { + t.Fatalf("Failed to parse URL: %s", err) + } + i := NewIndices(log.NewNopLogger(), http.DefaultClient, u, false, true, "_all") + stats, err := i.fetchAndDecodeIndexStats() + if err != nil { + t.Fatalf("Failed to fetch or decode indices stats: %s", err) + } + t.Logf("[%s] Index Response: %+v", ver, stats) + if stats.Aliases["foo_1"] != nil { + t.Errorf("Wrong aliases for foo_1") + } + if !reflect.DeepEqual(stats.Aliases["foo_2"], []string{"foo_alias_2_1"}) { + t.Errorf("Wrong aliases for foo_2") + } + if !reflect.DeepEqual(stats.Aliases["foo_3"], []string{"foo_alias_3_1", "foo_alias_3_2"}) { + t.Errorf("Wrong aliases for foo_3") + } } } diff --git a/collector/nodes.go b/collector/nodes.go index 1a895b7c..7d648f86 100644 --- a/collector/nodes.go +++ b/collector/nodes.go @@ -16,7 +16,7 @@ package collector import ( "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "net/url" "path" @@ -29,10 +29,18 @@ import ( func getRoles(node NodeStatsNodeResponse) map[string]bool { // default settings (2.x) and map, which roles to consider roles := map[string]bool{ - "master": false, - "data": false, - "ingest": false, - "client": true, + "master": false, + "data": false, + "data_hot": false, + "data_warm": false, + "data_cold": false, + "data_frozen": false, + "data_content": false, + "ml": false, + "remote_cluster_client": false, + "transform": false, + "ingest": false, + "client": true, } // assumption: a 5.x node has at least one role, otherwise it's a 1.7 or 2.x node if len(node.Roles) > 0 { @@ -193,11 +201,11 @@ func NewNodes(logger log.Logger, client *http.Client, url *url.URL, all bool, no up: prometheus.NewGauge(prometheus.GaugeOpts{ Name: prometheus.BuildFQName(namespace, "node_stats", "up"), - Help: "Was the last scrape of the ElasticSearch nodes endpoint successful.", + Help: "Was the last scrape of the Elasticsearch nodes endpoint successful.", }), totalScrapes: prometheus.NewCounter(prometheus.CounterOpts{ Name: prometheus.BuildFQName(namespace, "node_stats", "total_scrapes"), - Help: "Current total ElasticSearch node scrapes.", + Help: "Current total Elasticsearch node scrapes.", }), jsonParseFailures: prometheus.NewCounter(prometheus.CounterOpts{ Name: prometheus.BuildFQName(namespace, "node_stats", "json_parse_failures"), @@ -1818,7 +1826,7 @@ func (c *Nodes) fetchAndDecodeNodeStats() (nodeStatsResponse, error) { defer func() { err = res.Body.Close() if err != nil { - _ = level.Warn(c.logger).Log( + level.Warn(c.logger).Log( "msg", "failed to close http.Client", "err", err, ) @@ -1829,7 +1837,7 @@ func (c *Nodes) fetchAndDecodeNodeStats() (nodeStatsResponse, error) { return nsr, fmt.Errorf("HTTP Request failed with code %d", res.StatusCode) } - bts, err := ioutil.ReadAll(res.Body) + bts, err := io.ReadAll(res.Body) if err != nil { c.jsonParseFailures.Inc() return nsr, err @@ -1854,7 +1862,7 @@ func (c *Nodes) Collect(ch chan<- prometheus.Metric) { nodeStatsResp, err := c.fetchAndDecodeNodeStats() if err != nil { c.up.Set(0) - _ = level.Warn(c.logger).Log( + level.Warn(c.logger).Log( "msg", "failed to fetch and decode node stats", "err", err, ) @@ -1866,8 +1874,8 @@ func (c *Nodes) Collect(ch chan<- prometheus.Metric) { // Handle the node labels metric roles := getRoles(node) - for _, role := range []string{"master", "data", "client", "ingest"} { - if roles[role] { + for role, roleEnabled := range roles { + if roleEnabled { metric := createRoleMetric(role) ch <- prometheus.MustNewConstMetric( metric.Desc, diff --git a/collector/nodes_test.go b/collector/nodes_test.go index 26bca30e..3b4e4a5a 100644 --- a/collector/nodes_test.go +++ b/collector/nodes_test.go @@ -16,10 +16,10 @@ package collector import ( "encoding/base64" "fmt" - "io/ioutil" "net/http" "net/http/httptest" "net/url" + "os" "strings" "testing" @@ -29,7 +29,7 @@ import ( func TestNodesStats(t *testing.T) { for _, ver := range testElasticsearchVersions { filename := fmt.Sprintf("../fixtures/nodestats/%s.json", ver) - data, _ := ioutil.ReadFile(filename) + data, _ := os.ReadFile(filename) handlers := map[string]http.Handler{ "plain": http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { diff --git a/collector/shards.go b/collector/shards.go index 31f8934a..ba9a0ad2 100644 --- a/collector/shards.go +++ b/collector/shards.go @@ -105,7 +105,7 @@ func (s *Shards) getAndParseURL(u *url.URL) ([]ShardResponse, error) { defer func() { err = res.Body.Close() if err != nil { - _ = level.Warn(s.logger).Log( + level.Warn(s.logger).Log( "msg", "failed to close http.Client", "err", err, ) @@ -146,7 +146,7 @@ func (s *Shards) Collect(ch chan<- prometheus.Metric) { sr, err := s.fetchAndDecodeShards() if err != nil { - _ = level.Warn(s.logger).Log( + level.Warn(s.logger).Log( "msg", "failed to fetch and decode node shards stats", "err", err, ) diff --git a/collector/slm.go b/collector/slm.go index 84465517..47e6bd67 100644 --- a/collector/slm.go +++ b/collector/slm.go @@ -16,7 +16,7 @@ package collector import ( "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "net/url" "path" @@ -78,11 +78,11 @@ func NewSLM(logger log.Logger, client *http.Client, url *url.URL) *SLM { up: prometheus.NewGauge(prometheus.GaugeOpts{ Name: prometheus.BuildFQName(namespace, "slm_stats", "up"), - Help: "Was the last scrape of the ElasticSearch SLM endpoint successful.", + Help: "Was the last scrape of the Elasticsearch SLM endpoint successful.", }), totalScrapes: prometheus.NewCounter(prometheus.CounterOpts{ Name: prometheus.BuildFQName(namespace, "slm_stats", "total_scrapes"), - Help: "Current total ElasticSearch SLM scrapes.", + Help: "Current total Elasticsearch SLM scrapes.", }), jsonParseFailures: prometheus.NewCounter(prometheus.CounterOpts{ Name: prometheus.BuildFQName(namespace, "slm_stats", "json_parse_failures"), @@ -276,7 +276,7 @@ func (s *SLM) fetchAndDecodeSLMStats() (SLMStatsResponse, error) { defer func() { err = res.Body.Close() if err != nil { - _ = level.Warn(s.logger).Log( + level.Warn(s.logger).Log( "msg", "failed to close http.Client", "err", err, ) @@ -287,7 +287,7 @@ func (s *SLM) fetchAndDecodeSLMStats() (SLMStatsResponse, error) { return ssr, fmt.Errorf("HTTP Request failed with code %d", res.StatusCode) } - bts, err := ioutil.ReadAll(res.Body) + bts, err := io.ReadAll(res.Body) if err != nil { s.jsonParseFailures.Inc() return ssr, err @@ -315,7 +315,7 @@ func (s *SLM) fetchAndDecodeSLMStatus() (SLMStatusResponse, error) { defer func() { err = res.Body.Close() if err != nil { - _ = level.Warn(s.logger).Log( + level.Warn(s.logger).Log( "msg", "failed to close http.Client", "err", err, ) @@ -326,7 +326,7 @@ func (s *SLM) fetchAndDecodeSLMStatus() (SLMStatusResponse, error) { return ssr, fmt.Errorf("HTTP Request failed with code %d", res.StatusCode) } - bts, err := ioutil.ReadAll(res.Body) + bts, err := io.ReadAll(res.Body) if err != nil { s.jsonParseFailures.Inc() return ssr, err @@ -352,7 +352,7 @@ func (s *SLM) Collect(ch chan<- prometheus.Metric) { slmStatusResp, err := s.fetchAndDecodeSLMStatus() if err != nil { s.up.Set(0) - _ = level.Warn(s.logger).Log( + level.Warn(s.logger).Log( "msg", "failed to fetch and decode slm status", "err", err, ) @@ -362,7 +362,7 @@ func (s *SLM) Collect(ch chan<- prometheus.Metric) { slmStatsResp, err := s.fetchAndDecodeSLMStats() if err != nil { s.up.Set(0) - _ = level.Warn(s.logger).Log( + level.Warn(s.logger).Log( "msg", "failed to fetch and decode slm stats", "err", err, ) diff --git a/collector/snapshots.go b/collector/snapshots.go index 90d3e25d..fbf2c6eb 100644 --- a/collector/snapshots.go +++ b/collector/snapshots.go @@ -16,7 +16,7 @@ package collector import ( "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "net/url" "path" @@ -73,11 +73,11 @@ func NewSnapshots(logger log.Logger, client *http.Client, url *url.URL) *Snapsho up: prometheus.NewGauge(prometheus.GaugeOpts{ Name: prometheus.BuildFQName(namespace, "snapshot_stats", "up"), - Help: "Was the last scrape of the ElasticSearch snapshots endpoint successful.", + Help: "Was the last scrape of the Elasticsearch snapshots endpoint successful.", }), totalScrapes: prometheus.NewCounter(prometheus.CounterOpts{ Name: prometheus.BuildFQName(namespace, "snapshot_stats", "total_scrapes"), - Help: "Current total ElasticSearch snapshots scrapes.", + Help: "Current total Elasticsearch snapshots scrapes.", }), jsonParseFailures: prometheus.NewCounter(prometheus.CounterOpts{ Name: prometheus.BuildFQName(namespace, "snapshot_stats", "json_parse_failures"), @@ -239,7 +239,7 @@ func (s *Snapshots) getAndParseURL(u *url.URL, data interface{}) error { defer func() { err = res.Body.Close() if err != nil { - _ = level.Warn(s.logger).Log( + level.Warn(s.logger).Log( "msg", "failed to close http.Client", "err", err, ) @@ -250,7 +250,7 @@ func (s *Snapshots) getAndParseURL(u *url.URL, data interface{}) error { return fmt.Errorf("HTTP Request failed with code %d", res.StatusCode) } - bts, err := ioutil.ReadAll(res.Body) + bts, err := io.ReadAll(res.Body) if err != nil { s.jsonParseFailures.Inc() return err @@ -300,7 +300,7 @@ func (s *Snapshots) Collect(ch chan<- prometheus.Metric) { snapshotsStatsResp, err := s.fetchAndDecodeSnapshotsStats() if err != nil { s.up.Set(0) - _ = level.Warn(s.logger).Log( + level.Warn(s.logger).Log( "msg", "failed to fetch and decode snapshot stats", "err", err, ) diff --git a/examples/grafana/dashboard.json b/examples/grafana/dashboard.json index 66f2ab1a..6b1de5a8 100644 --- a/examples/grafana/dashboard.json +++ b/examples/grafana/dashboard.json @@ -2244,7 +2244,7 @@ ] }, "timezone": "utc", - "title": "ElasticSearch", + "title": "Elasticsearch", "uid": "n_nxrE_mk", "version": 2 } diff --git a/examples/prometheus/elasticsearch.rules b/examples/prometheus/elasticsearch.rules index a7922357..05109067 100644 --- a/examples/prometheus/elasticsearch.rules +++ b/examples/prometheus/elasticsearch.rules @@ -7,11 +7,11 @@ ALERT ElasticsearchTooFewNodesRunning IF elasticsearch_cluster_health_number_of_nodes < 3 FOR 5m LABELS {severity="critical"} - ANNOTATIONS {description="There are only {{$value}} < 3 ElasticSearch nodes running", summary="ElasticSearch running on less than 3 nodes"} + ANNOTATIONS {description="There are only {{$value}} < 3 Elasticsearch nodes running", summary="Elasticsearch running on less than 3 nodes"} # alert if heap usage is over 90% ALERT ElasticsearchHeapTooHigh IF elasticsearch_jvm_memory_used_bytes{area="heap"} / elasticsearch_jvm_memory_max_bytes{area="heap"} > 0.9 FOR 15m LABELS {severity="critical"} - ANNOTATIONS {description="The heap usage is over 90% for 15m", summary="ElasticSearch node {{$labels.node}} heap usage is high"} + ANNOTATIONS {description="The heap usage is over 90% for 15m", summary="Elasticsearch node {{$labels.node}} heap usage is high"} diff --git a/examples/prometheus/elasticsearch.rules.yml b/examples/prometheus/elasticsearch.rules.yml index 308048c3..d29f0b75 100644 --- a/examples/prometheus/elasticsearch.rules.yml +++ b/examples/prometheus/elasticsearch.rules.yml @@ -12,8 +12,8 @@ groups: labels: severity: critical annotations: - description: There are only {{$value}} < 3 ElasticSearch nodes running - summary: ElasticSearch running on less than 3 nodes + description: There are only {{$value}} < 3 Elasticsearch nodes running + summary: Elasticsearch running on less than 3 nodes - alert: ElasticsearchHeapTooHigh expr: elasticsearch_jvm_memory_used_bytes{area="heap"} / elasticsearch_jvm_memory_max_bytes{area="heap"} > 0.9 @@ -22,4 +22,4 @@ groups: severity: critical annotations: description: The heap usage is over 90% for 15m - summary: ElasticSearch node {{$labels.node}} heap usage is high + summary: Elasticsearch node {{$labels.node}} heap usage is high diff --git a/fixtures/settings-7.3.0.json b/fixtures/settings-7.3.0.json index 13673b55..94be09d1 100644 --- a/fixtures/settings-7.3.0.json +++ b/fixtures/settings-7.3.0.json @@ -48,11 +48,11 @@ "total_shards_per_node": "-1", "type": "balanced", "disk": { - "threshold_enabled": "true", + "threshold_enabled": "false", "watermark": { - "low": "85%", - "flood_stage": "95%", - "high": "90%" + "low": "0.85", + "flood_stage": "0.95", + "high": "0.9" }, "include_relocations": "true", "reroute_interval": "60s" diff --git a/fixtures/settings-persistent-clustermaxshardspernode-7.17.5.json b/fixtures/settings-persistent-clustermaxshardspernode-7.17.5.json new file mode 100644 index 00000000..52c489f8 --- /dev/null +++ b/fixtures/settings-persistent-clustermaxshardspernode-7.17.5.json @@ -0,0 +1,1527 @@ +{ + "persistent": { + "cluster": { + "max_shards_per_node": "1000" + } + }, + "transient": {}, + "defaults": { + "cluster": { + "max_voting_config_exclusions": "10", + "auto_shrink_voting_configuration": "true", + "election": { + "duration": "500ms", + "initial_timeout": "100ms", + "max_timeout": "10s", + "back_off_time": "100ms", + "strategy": "supports_voting_only" + }, + "no_master_block": "write", + "persistent_tasks": { + "allocation": { + "enable": "all", + "recheck_interval": "30s" + } + }, + "blocks": { + "read_only_allow_delete": "false", + "read_only": "false" + }, + "remote": { + "node": { + "attr": "" + }, + "initial_connect_timeout": "30s", + "connect": "true", + "connections_per_cluster": "3" + }, + "follower_lag": { + "timeout": "90000ms" + }, + "routing": { + "use_adaptive_replica_selection": "true", + "rebalance": { + "enable": "all" + }, + "allocation": { + "enforce_default_tier_preference": "false", + "node_concurrent_incoming_recoveries": "2", + "include": { + "_tier": "" + }, + "node_initial_primaries_recoveries": "4", + "same_shard": { + "host": "false" + }, + "total_shards_per_node": "-1", + "require": { + "_tier": "" + }, + "shard_state": { + "reroute": { + "priority": "NORMAL" + } + }, + "type": "balanced", + "disk": { + "threshold_enabled": "true", + "watermark": { + "flood_stage.frozen.max_headroom": "20GB", + "flood_stage": "100b", + "high": "200gb", + "low": "50mb", + "enable_for_single_data_node": "false", + "flood_stage.frozen": "95%" + }, + "include_relocations": "true", + "reroute_interval": "60s" + }, + "awareness": { + "attributes": [] + }, + "balance": { + "index": "0.55", + "threshold": "1.0", + "shard": "0.45" + }, + "enable": "all", + "node_concurrent_outgoing_recoveries": "2", + "allow_rebalance": "indices_all_active", + "cluster_concurrent_rebalance": "2", + "node_concurrent_recoveries": "2", + "exclude": { + "_tier": "" + } + } + }, + "indices": { + "tombstones": { + "size": "500" + }, + "close": { + "enable": "true" + } + }, + "nodes": { + "reconnect_interval": "10s" + }, + "service": { + "master_service_starvation_logging_threshold": "5m", + "slow_master_task_logging_threshold": "10s", + "slow_task_logging_threshold": "30s" + }, + "publish": { + "timeout": "30000ms", + "info_timeout": "10000ms" + }, + "name": "docker-cluster", + "fault_detection": { + "leader_check": { + "interval": "1000ms", + "timeout": "10000ms", + "retry_count": "3" + }, + "follower_check": { + "interval": "1000ms", + "timeout": "10000ms", + "retry_count": "3" + } + }, + "join": { + "timeout": "60000ms" + }, + "max_shards_per_node": { + "frozen": "3000" + }, + "initial_master_nodes": [], + "deprecation_indexing": { + "enabled": "true", + "x_opaque_id_used": { + "enabled": "true" + } + }, + "snapshot": { + "info": { + "max_concurrent_fetches": "5" + } + }, + "info": { + "update": { + "interval": "30s", + "timeout": "15s" + } + } + }, + "stack": { + "templates": { + "enabled": "true" + } + }, + "logger": { + "level": "INFO" + }, + "bootstrap": { + "memory_lock": "false", + "system_call_filter": "true", + "ctrlhandler": "true" + }, + "processors": "12", + "ingest": { + "user_agent": { + "cache_size": "1000" + }, + "geoip": { + "cache_size": "1000", + "downloader": { + "enabled": "true", + "endpoint": "https://geoip.elastic.co/v1/database", + "poll": { + "interval": "3d" + } + } + }, + "grok": { + "watchdog": { + "max_execution_time": "1s", + "interval": "1s" + } + } + }, + "network": { + "host": [ + "0.0.0.0" + ], + "tcp": { + "reuse_address": "true", + "keep_count": "-1", + "connect_timeout": "30s", + "keep_interval": "-1", + "no_delay": "true", + "keep_alive": "true", + "receive_buffer_size": "-1b", + "keep_idle": "-1", + "send_buffer_size": "-1b" + }, + "bind_host": [ + "0.0.0.0" + ], + "server": "true", + "breaker": { + "inflight_requests": { + "limit": "100%", + "overhead": "2.0" + } + }, + "publish_host": [ + "0.0.0.0" + ] + }, + "pidfile": "", + "searchable_snapshots": { + "blob_cache": { + "periodic_cleanup": { + "interval": "1h", + "batch_size": "100", + "pit_keep_alive": "10m", + "retention_period": "1h" + } + } + }, + "path": { + "data": [], + "logs": "/usr/share/elasticsearch/logs", + "shared_data": "", + "home": "/usr/share/elasticsearch", + "repo": [] + }, + "search": { + "default_search_timeout": "-1", + "max_open_scroll_context": "500", + "max_buckets": "65536", + "max_async_search_response_size": "-1b", + "keep_alive_interval": "1m", + "remote": { + "node": { + "attr": "" + }, + "initial_connect_timeout": "30s", + "connect": "true", + "connections_per_cluster": "3" + }, + "max_keep_alive": "24h", + "highlight": { + "term_vector_multi_value": "true" + }, + "default_allow_partial_results": "true", + "low_level_cancellation": "true", + "allow_expensive_queries": "true", + "default_keep_alive": "5m", + "aggs": { + "rewrite_to_filter_by_filter": "true" + } + }, + "security": { + "manager": { + "filter_bad_defaults": "true" + } + }, + "ccr": { + "wait_for_metadata_timeout": "60s", + "indices": { + "recovery": { + "recovery_activity_timeout": "60s", + "chunk_size": "1mb", + "internal_action_timeout": "60s", + "max_bytes_per_sec": "40mb", + "max_concurrent_file_chunks": "5" + } + }, + "auto_follow": { + "wait_for_metadata_timeout": "60s" + } + }, + "repositories": { + "fs": { + "compress": "false", + "chunk_size": "9223372036854775807b", + "location": "" + }, + "url": { + "supported_protocols": [ + "http", + "https", + "ftp", + "file", + "jar" + ], + "allowed_urls": [], + "url": "http:" + } + }, + "action": { + "auto_create_index": "true", + "search": { + "pre_filter_shard_size": { + "default": "128" + }, + "shard_count": { + "limit": "9223372036854775807" + } + }, + "destructive_requires_name": "false" + }, + "client": { + "type": "node", + "transport": { + "ignore_cluster_name": "false", + "nodes_sampler_interval": "5s", + "sniff": "false", + "ping_timeout": "5s" + } + }, + "enrich": { + "max_force_merge_attempts": "3", + "cleanup_period": "15m", + "fetch_size": "10000", + "cache_size": "1000", + "coordinator_proxy": { + "max_concurrent_requests": "8", + "max_lookups_per_request": "128", + "queue_capacity": "1024" + }, + "max_concurrent_policy_executions": "50" + }, + "xpack": { + "flattened": { + "enabled": "true" + }, + "watcher": { + "execution": { + "scroll": { + "size": "0", + "timeout": "" + }, + "default_throttle_period": "5s" + }, + "internal": { + "ops": { + "bulk": { + "default_timeout": "" + }, + "index": { + "default_timeout": "" + }, + "search": { + "default_timeout": "" + } + } + }, + "thread_pool": { + "queue_size": "1000", + "size": "50" + }, + "index": { + "rest": { + "direct_access": "" + } + }, + "use_ilm_index_management": "true", + "history": { + "cleaner_service": { + "enabled": "true" + } + }, + "trigger": { + "schedule": { + "ticker": { + "tick_interval": "500ms" + } + } + }, + "enabled": "true", + "input": { + "search": { + "default_timeout": "" + } + }, + "encrypt_sensitive_data": "false", + "transform": { + "search": { + "default_timeout": "" + } + }, + "stop": { + "timeout": "30s" + }, + "watch": { + "scroll": { + "size": "0" + } + }, + "bulk": { + "concurrent_requests": "0", + "flush_interval": "1s", + "size": "1mb", + "actions": "1" + }, + "actions": { + "bulk": { + "default_timeout": "" + }, + "index": { + "default_timeout": "" + } + } + }, + "eql": { + "enabled": "true" + }, + "data_frame": { + "enabled": "true" + }, + "ilm": { + "enabled": "true" + }, + "monitoring": { + "migration": { + "decommission_alerts": "false" + }, + "collection": { + "cluster": { + "stats": { + "timeout": "10s" + } + }, + "node": { + "stats": { + "timeout": "10s" + } + }, + "indices": [], + "ccr": { + "stats": { + "timeout": "10s" + } + }, + "enrich": { + "stats": { + "timeout": "10s" + } + }, + "index": { + "stats": { + "timeout": "10s" + }, + "recovery": { + "active_only": "false", + "timeout": "10s" + } + }, + "interval": "10s", + "enabled": "false", + "ml": { + "job": { + "stats": { + "timeout": "10s" + } + } + } + }, + "history": { + "duration": "168h" + }, + "elasticsearch": { + "collection": { + "enabled": "true" + } + }, + "enabled": "true" + }, + "graph": { + "enabled": "true" + }, + "searchable": { + "snapshot": { + "allocate_on_rolling_restart": "false", + "cache": { + "range_size": "32mb", + "sync": { + "max_files": "10000", + "interval": "60s", + "shutdown_timeout": "10s" + }, + "recovery_range_size": "128kb" + }, + "shared_cache": { + "recovery_range_size": "128kb", + "region_size": "16mb", + "size": "0", + "min_time_delta": "60s", + "decay": { + "interval": "60s" + }, + "size.max_headroom": "-1", + "range_size": "16mb", + "max_freq": "100" + } + } + }, + "rollup": { + "enabled": "true", + "task_thread_pool": { + "queue_size": "-1", + "size": "1" + } + }, + "sql": { + "enabled": "true" + }, + "searchable_snapshots": { + "cache_fetch_async_thread_pool": { + "core": "0", + "max": "36", + "keep_alive": "30s" + }, + "cache_prewarming_thread_pool": { + "core": "0", + "max": "16", + "keep_alive": "30s" + } + }, + "license": { + "upload": { + "types": [ + "standard", + "gold", + "platinum", + "enterprise", + "trial" + ] + }, + "self_generated": { + "type": "basic" + } + }, + "logstash": { + "enabled": "true" + }, + "notification": { + "pagerduty": { + "default_account": "" + }, + "email": { + "account": { + "domain_allowlist": [ + "*" + ] + }, + "default_account": "", + "html": { + "sanitization": { + "allow": [ + "body", + "head", + "_tables", + "_links", + "_blocks", + "_formatting", + "img:embedded" + ], + "disallow": [], + "enabled": "true" + } + } + }, + "reporting": { + "retries": "40", + "warning": { + "enabled": "true" + }, + "interval": "15s" + }, + "jira": { + "default_account": "" + }, + "slack": { + "default_account": "" + } + }, + "security": { + "operator_privileges": { + "enabled": "false" + }, + "dls_fls": { + "enabled": "true" + }, + "dls": { + "bitset": { + "cache": { + "size": "10%", + "ttl": "2h" + } + } + }, + "transport": { + "filter": { + "allow": [], + "deny": [], + "enabled": "true" + }, + "ssl": { + "enabled": "false" + } + }, + "ssl": { + "diagnose": { + "trust": "true" + } + }, + "enabled": "true", + "crypto": { + "thread_pool": { + "queue_size": "1000", + "size": "6" + } + }, + "filter": { + "always_allow_bound_address": "true" + }, + "encryption": { + "algorithm": "AES/CTR/NoPadding" + }, + "audit": { + "enabled": "false", + "logfile": { + "emit_node_id": "true", + "emit_node_host_name": "false", + "emit_node_name": "false", + "events": { + "emit_request_body": "false", + "include": [ + "ACCESS_DENIED", + "ACCESS_GRANTED", + "ANONYMOUS_ACCESS_DENIED", + "AUTHENTICATION_FAILED", + "CONNECTION_DENIED", + "TAMPERED_REQUEST", + "RUN_AS_DENIED", + "RUN_AS_GRANTED", + "SECURITY_CONFIG_CHANGE" + ], + "exclude": [] + }, + "emit_node_host_address": "false" + } + }, + "authc": { + "password_hashing": { + "algorithm": "bcrypt" + }, + "success_cache": { + "size": "10000", + "enabled": "true", + "expire_after_access": "1h" + }, + "api_key": { + "doc_cache": { + "ttl": "5m" + }, + "cache": { + "hash_algo": "ssha256", + "max_keys": "25000", + "ttl": "24h" + }, + "delete": { + "interval": "24h", + "timeout": "-1" + }, + "enabled": "false", + "hashing": { + "algorithm": "pbkdf2" + } + }, + "anonymous": { + "authz_exception": "true", + "roles": [], + "username": "_anonymous" + }, + "run_as": { + "enabled": "true" + }, + "reserved_realm": { + "enabled": "true" + }, + "service_token": { + "cache": { + "hash_algo": "ssha256", + "max_tokens": "100000", + "ttl": "20m" + } + }, + "token": { + "delete": { + "interval": "30m", + "timeout": "-1" + }, + "enabled": "false", + "thread_pool": { + "queue_size": "1000", + "size": "1" + }, + "timeout": "20m" + } + }, + "fips_mode": { + "enabled": "false" + }, + "encryption_key": { + "length": "128", + "algorithm": "AES" + }, + "http": { + "filter": { + "allow": [], + "deny": [], + "enabled": "true" + }, + "ssl": { + "enabled": "false" + } + }, + "automata": { + "max_determinized_states": "100000", + "cache": { + "size": "10000", + "ttl": "48h", + "enabled": "true" + } + }, + "user": null, + "authz": { + "timer": { + "indices": { + "enabled": "false", + "threshold": { + "warn": "200ms", + "debug": "20ms", + "info": "100ms" + } + } + }, + "store": { + "privileges": { + "cache": { + "ttl": "24h", + "max_size": "10000" + } + }, + "roles": { + "index": { + "cache": { + "ttl": "20m", + "max_size": "10000" + } + }, + "cache": { + "max_size": "10000" + }, + "negative_lookup_cache": { + "max_size": "10000" + }, + "field_permissions": { + "cache": { + "max_size_in_bytes": "104857600" + } + } + } + } + } + }, + "transform": { + "num_transform_failure_retries": "10", + "enabled": "true" + }, + "vectors": { + "enabled": "true" + }, + "ccr": { + "enabled": "true", + "ccr_thread_pool": { + "queue_size": "100", + "size": "32" + } + }, + "idp": { + "privileges": { + "application": "", + "cache": { + "size": "100", + "ttl": "90m" + } + }, + "metadata": { + "signing": { + "keystore": { + "alias": "" + } + } + }, + "slo_endpoint": { + "post": "https:", + "redirect": "https:" + }, + "defaults": { + "nameid_format": "urn:oasis:names:tc:SAML:2.0:nameid-format:transient", + "authn_expiry": "5m" + }, + "allowed_nameid_formats": [ + "urn:oasis:names:tc:SAML:2.0:nameid-format:transient" + ], + "contact": { + "given_name": "", + "email": "", + "surname": "" + }, + "organization": { + "display_name": "", + "name": "", + "url": "http:" + }, + "sso_endpoint": { + "post": "https:", + "redirect": "https:" + }, + "entity_id": "", + "signing": { + "keystore": { + "alias": "" + } + }, + "sp": { + "cache": { + "size": "1000", + "ttl": "60m" + }, + "wildcard": { + "path": "wildcard_services.json" + } + }, + "enabled": "false" + }, + "slm": { + "enabled": "true" + }, + "enrich": { + "enabled": "true" + }, + "http": { + "tcp": { + "keep_alive": "true" + }, + "default_connection_timeout": "10s", + "proxy": { + "host": "", + "scheme": "", + "port": "0" + }, + "connection_pool_ttl": "-1", + "max_response_size": "10mb", + "whitelist": [ + "*" + ], + "default_read_timeout": "10s" + }, + "autoscaling": { + "memory": { + "monitor": { + "timeout": "15s" + } + } + }, + "ml": { + "utility_thread_pool": { + "core": "1", + "max": "2048", + "keep_alive": "10m" + }, + "max_anomaly_records": "500", + "enable_config_migration": "true", + "max_open_jobs": "512", + "delayed_data_check_freq": "15m", + "min_disk_space_off_heap": "5gb", + "use_auto_machine_memory_percent": "false", + "inference_model": { + "cache_size": "40%", + "time_to_live": "5m" + }, + "nightly_maintenance_requests_per_second": "-1.0", + "node_concurrent_job_allocations": "2", + "max_model_memory_limit": "0b", + "enabled": "true", + "max_lazy_ml_nodes": "0", + "max_ml_node_size": "0b", + "max_machine_memory_percent": "30", + "persist_results_max_retries": "20", + "autodetect_process": "true", + "datafeed_thread_pool": { + "core": "1", + "max": "512", + "keep_alive": "1m" + }, + "max_inference_processors": "50", + "process_connect_timeout": "10s", + "job_comms_thread_pool": { + "core": "4", + "max": "2048", + "keep_alive": "1m" + } + } + }, + "rest": { + "action": { + "multi": { + "allow_explicit_index": "true" + } + } + }, + "cache": { + "recycler": { + "page": { + "limit": { + "heap": "10%" + }, + "type": "CONCURRENT", + "weight": { + "longs": "1.0", + "ints": "1.0", + "bytes": "1.0", + "objects": "0.1" + } + } + } + }, + "async_search": { + "index_cleanup_interval": "1h" + }, + "reindex": { + "remote": { + "whitelist": [] + } + }, + "resource": { + "reload": { + "enabled": "true", + "interval": { + "low": "60s", + "high": "5s", + "medium": "30s" + } + } + }, + "thread_pool": { + "force_merge": { + "queue_size": "-1", + "size": "1" + }, + "search_coordination": { + "queue_size": "1000", + "size": "5" + }, + "snapshot_meta": { + "core": "1", + "max": "36", + "keep_alive": "30s" + }, + "fetch_shard_started": { + "core": "1", + "max": "24", + "keep_alive": "5m" + }, + "listener": { + "queue_size": "-1", + "size": "6" + }, + "estimated_time_interval.warn_threshold": "5s", + "scheduler": { + "warn_threshold": "5s" + }, + "search": { + "max_queue_size": "1000", + "queue_size": "1000", + "size": "19", + "auto_queue_frame_size": "2000", + "target_response_time": "1s", + "min_queue_size": "1000" + }, + "fetch_shard_store": { + "core": "1", + "max": "24", + "keep_alive": "5m" + }, + "flush": { + "core": "1", + "max": "5", + "keep_alive": "5m" + }, + "vectortile": { + "queue_size": "-1", + "size": "1" + }, + "get": { + "queue_size": "1000", + "size": "12" + }, + "system_read": { + "queue_size": "2000", + "size": "5" + }, + "system_critical_read": { + "queue_size": "2000", + "size": "5" + }, + "estimated_time_interval": "200ms", + "write": { + "queue_size": "10000", + "size": "12" + }, + "system_critical_write": { + "queue_size": "1500", + "size": "5" + }, + "refresh": { + "core": "1", + "max": "6", + "keep_alive": "5m" + }, + "system_write": { + "queue_size": "1000", + "size": "5" + }, + "generic": { + "core": "4", + "max": "128", + "keep_alive": "30s" + }, + "warmer": { + "core": "1", + "max": "5", + "keep_alive": "5m" + }, + "auto_complete": { + "queue_size": "100", + "size": "3" + }, + "management": { + "core": "1", + "max": "5", + "keep_alive": "5m" + }, + "analyze": { + "queue_size": "16", + "size": "1" + }, + "snapshot": { + "core": "1", + "max": "5", + "keep_alive": "5m" + }, + "search_throttled": { + "max_queue_size": "100", + "queue_size": "100", + "size": "1", + "auto_queue_frame_size": "200", + "target_response_time": "1s", + "min_queue_size": "100" + } + }, + "index": { + "codec": "default", + "recovery": { + "type": "" + }, + "store": { + "type": "", + "fs": { + "fs_lock": "native" + }, + "preload": [], + "snapshot": { + "uncached_chunk_size": "-1b", + "cache": { + "excluded_file_types": [] + } + } + } + }, + "monitor": { + "jvm": { + "gc": { + "enabled": "true", + "overhead": { + "warn": "50", + "debug": "10", + "info": "25" + }, + "refresh_interval": "1s" + }, + "refresh_interval": "1s" + }, + "process": { + "refresh_interval": "1s" + }, + "os": { + "refresh_interval": "1s" + }, + "fs": { + "health": { + "enabled": "true", + "refresh_interval": "120s", + "slow_path_logging_threshold": "5s" + }, + "refresh_interval": "1s" + } + }, + "runtime_fields": { + "grok": { + "watchdog": { + "max_execution_time": "1s", + "interval": "1s" + } + } + }, + "transport": { + "tcp": { + "reuse_address": "true", + "keep_count": "-1", + "connect_timeout": "30s", + "keep_interval": "-1", + "compress": "FALSE", + "port": "9300-9400", + "no_delay": "true", + "keep_alive": "true", + "receive_buffer_size": "-1b", + "keep_idle": "-1", + "send_buffer_size": "-1b" + }, + "bind_host": [], + "connect_timeout": "30s", + "compress": "FALSE", + "ping_schedule": "-1", + "connections_per_node": { + "recovery": "2", + "state": "1", + "bulk": "3", + "reg": "6", + "ping": "1" + }, + "tracer": { + "include": [], + "exclude": [ + "internal:discovery/zen/fd*", + "internal:coordination/fault_detection/*", + "cluster:monitor/nodes/liveness" + ] + }, + "type": "security4", + "slow_operation_logging_threshold": "5s", + "type.default": "netty4", + "features": { + "x-pack": "true" + }, + "port": "9300-9400", + "compression_scheme": "DEFLATE", + "host": [], + "publish_port": "-1", + "tcp_no_delay": "true", + "publish_host": [], + "netty": { + "receive_predictor_size": "64kb", + "receive_predictor_max": "64kb", + "worker_count": "12", + "receive_predictor_min": "64kb", + "boss_count": "1" + } + }, + "deprecation": { + "skip_deprecated_settings": [] + }, + "script": { + "allowed_contexts": [], + "max_compilations_rate": "150/5m", + "cache": { + "max_size": "3000", + "expire": "0ms" + }, + "painless": { + "regex": { + "enabled": "limited", + "limit-factor": "6" + } + }, + "max_size_in_bytes": "65535", + "allowed_types": [], + "disable_max_compilations_rate": "false" + }, + "indexing_pressure": { + "memory": { + "limit": "10%" + } + }, + "node": { + "data": "true", + "bandwidth": { + "recovery": { + "disk": { + "write": "-1", + "read": "-1" + }, + "operator": { + "factor.read": "0.4", + "factor.write": "0.4", + "factor": "0.4", + "factor.max_overcommit": "100.0" + }, + "network": "-1" + } + }, + "roles": [ + "data_frozen", + "data_warm", + "transform", + "data", + "remote_cluster_client", + "data_cold", + "data_content", + "data_hot", + "ingest", + "master", + "ml" + ], + "max_local_storage_nodes": "1", + "processors": "12", + "store": { + "allow_mmap": "true" + }, + "ingest": "true", + "master": "true", + "pidfile": "", + "transform": "true", + "remote_cluster_client": "true", + "enable_lucene_segment_infos_trace": "false", + "local_storage": "true", + "name": "36ac32055483", + "id": { + "seed": "0" + }, + "voting_only": "false", + "attr": { + "transform": { + "node": "true" + }, + "xpack": { + "installed": "true" + }, + "ml": { + "max_jvm_size": "8392802304", + "machine_memory": "16784928768", + "max_open_jobs": "512" + } + }, + "portsfile": "false", + "ml": "true" + }, + "indices": { + "replication": { + "retry_timeout": "60s", + "initial_retry_backoff_bound": "50ms" + }, + "cache": { + "cleanup_interval": "1m" + }, + "mapping": { + "dynamic_timeout": "30s", + "max_in_flight_updates": "10" + }, + "memory": { + "interval": "5s", + "max_index_buffer_size": "-1", + "shard_inactive_time": "5m", + "index_buffer_size": "10%", + "min_index_buffer_size": "48mb" + }, + "breaker": { + "request": { + "limit": "60%", + "type": "memory", + "overhead": "1.0" + }, + "total": { + "limit": "95%", + "use_real_memory": "true" + }, + "accounting": { + "limit": "100%", + "overhead": "1.0" + }, + "fielddata": { + "limit": "40%", + "type": "memory", + "overhead": "1.03" + }, + "type": "hierarchy" + }, + "query": { + "bool": { + "max_nested_depth": "20", + "max_clause_count": "1024" + }, + "query_string": { + "analyze_wildcard": "false", + "allowLeadingWildcard": "true" + } + }, + "id_field_data": { + "enabled": "true" + }, + "recovery": { + "internal_action_retry_timeout": "1m", + "recovery_activity_timeout": "1800000ms", + "retry_delay_network": "5s", + "internal_action_timeout": "15m", + "max_concurrent_snapshot_file_downloads_per_node": "25", + "retry_delay_state_sync": "500ms", + "max_concurrent_snapshot_file_downloads": "5", + "internal_action_long_timeout": "1800000ms", + "max_concurrent_operations": "1", + "use_snapshots": "true", + "max_bytes_per_sec": "40mb", + "max_concurrent_file_chunks": "2" + }, + "requests": { + "cache": { + "size": "1%", + "expire": "0ms" + } + }, + "store": { + "delete": { + "shard": { + "timeout": "30s" + } + } + }, + "analysis": { + "hunspell": { + "dictionary": { + "ignore_case": "false", + "lazy": "false" + } + } + }, + "queries": { + "cache": { + "count": "10000", + "size": "10%", + "all_segments": "false" + } + }, + "lifecycle": { + "history_index_enabled": "true", + "poll_interval": "10m", + "step": { + "master_timeout": "30s" + } + }, + "fielddata": { + "cache": { + "size": "-1b" + } + } + }, + "plugin": { + "mandatory": [] + }, + "slm": { + "minimum_interval": "15m", + "retention_schedule": "0 30 1 * * ?", + "retention_duration": "1h", + "history_index_enabled": "true" + }, + "discovery": { + "seed_hosts": [], + "unconfigured_bootstrap_timeout": "3s", + "request_peers_timeout": "3000ms", + "zen": { + "commit_timeout": "30s", + "no_master_block": "write", + "join_retry_delay": "100ms", + "join_retry_attempts": "3", + "ping": { + "unicast": { + "concurrent_connects": "10", + "hosts": [], + "hosts.resolve_timeout": "5s" + } + }, + "master_election": { + "ignore_non_master_pings": "false", + "wait_for_joins_timeout": "30000ms" + }, + "send_leave_request": "true", + "ping_timeout": "3s", + "bwc_ping_timeout": "3s", + "join_timeout": "60000ms", + "publish_diff": { + "enable": "true" + }, + "publish": { + "max_pending_cluster_states": "25" + }, + "minimum_master_nodes": "-1", + "unsafe_rolling_upgrades_enabled": "true", + "hosts_provider": [], + "publish_timeout": "30s", + "fd": { + "connect_on_network_disconnect": "false", + "ping_interval": "1s", + "ping_retries": "3", + "register_connection_listener": "true", + "ping_timeout": "30s" + }, + "max_pings_from_another_master": "3" + }, + "initial_state_timeout": "30s", + "cluster_formation_warning_timeout": "10000ms", + "seed_providers": [], + "type": "single-node", + "seed_resolver": { + "max_concurrent_resolvers": "10", + "timeout": "5s" + }, + "find_peers_interval": "1000ms", + "probe": { + "connect_timeout": "30s", + "handshake_timeout": "30s" + } + }, + "http": { + "cors": { + "max-age": "1728000", + "allow-origin": "", + "allow-headers": "X-Requested-With,Content-Type,Content-Length", + "allow-credentials": "false", + "allow-methods": "OPTIONS,HEAD,GET,POST,PUT,DELETE", + "enabled": "false" + }, + "max_chunk_size": "8kb", + "compression_level": "3", + "max_initial_line_length": "4kb", + "type": "security4", + "pipelining": { + "max_events": "10000" + }, + "type.default": "netty4", + "content_type": { + "required": "true" + }, + "host": [], + "publish_port": "-1", + "read_timeout": "0ms", + "max_content_length": "100mb", + "netty": { + "receive_predictor_size": "64kb", + "max_composite_buffer_components": "69905", + "worker_count": "0" + }, + "tcp": { + "reuse_address": "true", + "keep_count": "-1", + "keep_interval": "-1", + "no_delay": "true", + "keep_alive": "true", + "receive_buffer_size": "-1b", + "keep_idle": "-1", + "send_buffer_size": "-1b" + }, + "bind_host": [], + "client_stats": { + "enabled": "true", + "closed_channels": { + "max_age": "5m", + "max_count": "10000" + } + }, + "reset_cookies": "false", + "max_warning_header_count": "-1", + "tracer": { + "include": [], + "exclude": [] + }, + "max_warning_header_size": "-1b", + "detailed_errors": { + "enabled": "true" + }, + "port": "9200-9300", + "max_header_size": "8kb", + "tcp_no_delay": "true", + "compression": "true", + "publish_host": [] + }, + "gateway": { + "recover_after_master_nodes": "0", + "expected_nodes": "-1", + "recover_after_data_nodes": "-1", + "expected_data_nodes": "-1", + "write_dangling_indices_info": "true", + "slow_write_logging_threshold": "10s", + "recover_after_time": "0ms", + "expected_master_nodes": "-1", + "recover_after_nodes": "-1", + "auto_import_dangling_indices": "false" + }, + "snapshot": { + "refresh_repo_uuid_on_restore": "true", + "max_concurrent_operations": "1000" + } + } +} diff --git a/go.mod b/go.mod index 20a1a5d7..ad4c7751 100644 --- a/go.mod +++ b/go.mod @@ -1,26 +1,51 @@ module github.com/prometheus-community/elasticsearch_exporter -go 1.17 +go 1.19 require ( - github.com/blang/semver v3.5.2-0.20180723201105-3c1074078d32+incompatible - github.com/go-kit/log v0.2.0 - github.com/imdario/mergo v0.3.12 - github.com/prometheus/client_golang v1.12.1 - github.com/prometheus/common v0.34.0 - gopkg.in/alecthomas/kingpin.v2 v2.2.6 + github.com/alecthomas/kingpin/v2 v2.3.2 + github.com/aws/aws-sdk-go-v2 v1.18.1 + github.com/aws/aws-sdk-go-v2/config v1.18.27 + github.com/aws/aws-sdk-go-v2/credentials v1.13.26 + github.com/aws/aws-sdk-go-v2/service/sts v1.19.2 + github.com/blang/semver/v4 v4.0.0 + github.com/go-kit/log v0.2.1 + github.com/imdario/mergo v0.3.13 + github.com/prometheus/client_golang v1.16.0 + github.com/prometheus/common v0.44.0 + github.com/prometheus/exporter-toolkit v0.10.0 ) require ( - github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect - github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect + github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.4 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.34 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.28 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.3.35 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.28 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.12.12 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.12 // indirect + github.com/aws/smithy-go v1.13.5 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/coreos/go-systemd/v22 v22.5.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logfmt/logfmt v0.5.1 // indirect - github.com/golang/protobuf v1.5.2 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect - github.com/prometheus/client_model v0.2.0 // indirect - github.com/prometheus/procfs v0.7.3 // indirect - golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect - google.golang.org/protobuf v1.26.0 // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/jpillora/backoff v1.0.0 // indirect + github.com/kr/text v0.2.0 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect + github.com/prometheus/client_model v0.4.0 // indirect + github.com/prometheus/procfs v0.10.1 // indirect + github.com/xhit/go-str2duration/v2 v2.1.0 // indirect + golang.org/x/crypto v0.8.0 // indirect + golang.org/x/net v0.10.0 // indirect + golang.org/x/oauth2 v0.8.0 // indirect + golang.org/x/sync v0.2.0 // indirect + golang.org/x/sys v0.8.0 // indirect + golang.org/x/text v0.9.0 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/protobuf v1.30.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index 9dd14644..5117c5f0 100644 --- a/go.sum +++ b/go.sum @@ -1,486 +1,118 @@ -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/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= -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 h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -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/alecthomas/kingpin/v2 v2.3.2 h1:H0aULhgmSzN8xQ3nX1uxtdlTHYoPLu5AhHxWrKI6ocU= +github.com/alecthomas/kingpin/v2 v2.3.2/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= +github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= +github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= +github.com/aws/aws-sdk-go-v2 v1.18.1 h1:+tefE750oAb7ZQGzla6bLkOwfcQCEtC5y2RqoqCeqKo= +github.com/aws/aws-sdk-go-v2 v1.18.1/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= +github.com/aws/aws-sdk-go-v2/config v1.18.27 h1:Az9uLwmssTE6OGTpsFqOnaGpLnKDqNYOJzWuC6UAYzA= +github.com/aws/aws-sdk-go-v2/config v1.18.27/go.mod h1:0My+YgmkGxeqjXZb5BYme5pc4drjTnM+x1GJ3zv42Nw= +github.com/aws/aws-sdk-go-v2/credentials v1.13.26 h1:qmU+yhKmOCyujmuPY7tf5MxR/RKyZrOPO3V4DobiTUk= +github.com/aws/aws-sdk-go-v2/credentials v1.13.26/go.mod h1:GoXt2YC8jHUBbA4jr+W3JiemnIbkXOfxSXcisUsZ3os= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.4 h1:LxK/bitrAr4lnh9LnIS6i7zWbCOdMsfzKFBI6LUCS0I= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.4/go.mod h1:E1hLXN/BL2e6YizK1zFlYd8vsfi2GTjbjBazinMmeaM= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.34 h1:A5UqQEmPaCFpedKouS4v+dHCTUo2sKqhoKO9U5kxyWo= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.34/go.mod h1:wZpTEecJe0Btj3IYnDx/VlUzor9wm3fJHyvLpQF0VwY= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.28 h1:srIVS45eQuewqz6fKKu6ZGXaq6FuFg5NzgQBAM6g8Y4= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.28/go.mod h1:7VRpKQQedkfIEXb4k52I7swUnZP0wohVajJMRn3vsUw= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.35 h1:LWA+3kDM8ly001vJ1X1waCuLJdtTl48gwkPKWy9sosI= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.35/go.mod h1:0Eg1YjxE0Bhn56lx+SHJwCzhW+2JGtizsrx+lCqrfm0= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.28 h1:bkRyG4a929RCnpVSTvLM2j/T4ls015ZhhYApbmYs15s= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.28/go.mod h1:jj7znCIg05jXlaGBlFMGP8+7UN3VtCkRBG2spnmRQkU= +github.com/aws/aws-sdk-go-v2/service/sso v1.12.12 h1:nneMBM2p79PGWBQovYO/6Xnc2ryRMw3InnDJq1FHkSY= +github.com/aws/aws-sdk-go-v2/service/sso v1.12.12/go.mod h1:HuCOxYsF21eKrerARYO6HapNeh9GBNq7fius2AcwodY= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.12 h1:2qTR7IFk7/0IN/adSFhYu9Xthr0zVFTgBrmPldILn80= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.12/go.mod h1:E4VrHCPzmVB/KFXtqBGKb3c8zpbNBgKe3fisDNLAW5w= +github.com/aws/aws-sdk-go-v2/service/sts v1.19.2 h1:XFJ2Z6sNUUcAz9poj+245DMkrHE4h2j5I9/xD50RHfE= +github.com/aws/aws-sdk-go-v2/service/sts v1.19.2/go.mod h1:dp0yLPsLBOi++WTxzCjA/oZqi6NPIhoR+uF7GeMU9eg= +github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8= +github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= 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/blang/semver v3.5.2-0.20180723201105-3c1074078d32+incompatible h1:8fBbhRkI5/0ocLFbrhPgnGUm0ogc+Gko1cRodPWDKX4= -github.com/blang/semver v3.5.2-0.20180723201105-3c1074078d32+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -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/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/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/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -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-kit/log v0.2.0 h1:7i2K3eKTos3Vc0enKCfnVcgHh2olr/MyfboYq7cAcFw= -github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -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-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= +github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/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/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= 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/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 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.5/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/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/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/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= -github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= +github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= 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/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -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/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/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/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/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/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/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/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/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -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/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.34.0 h1:RBmGO9d/FVjqHT0yUGQwBJhkwKV+wPCn7KGpvfab0uE= -github.com/prometheus/common v0.34.0/go.mod h1:gB3sOl7P0TvJabZpLY5uQMpUqRCPPCyRLCZYc7JZTNE= -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/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -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/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= +github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= +github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= +github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= +github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= +github.com/prometheus/exporter-toolkit v0.10.0 h1:yOAzZTi4M22ZzVxD+fhy1URTuNRj/36uQJJ5S8IPza8= +github.com/prometheus/exporter-toolkit v0.10.0/go.mod h1:+sVFzuvV5JDyw+Ih6p3zFxZNVnKQa3x5qPmDSiPu4ZY= +github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= +github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -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 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -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= -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= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc= +github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -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/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-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/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ= +golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= 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/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-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-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -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/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -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/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= +golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/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-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= +golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-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-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -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-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -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/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-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-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/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/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-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-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/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/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/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/yaml.v2 v2.2.2/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.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/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= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/main.go b/main.go index 3b121207..429cbcb0 100644 --- a/main.go +++ b/main.go @@ -23,13 +23,16 @@ import ( "context" + "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log/level" "github.com/prometheus-community/elasticsearch_exporter/collector" "github.com/prometheus-community/elasticsearch_exporter/pkg/clusterinfo" + "github.com/prometheus-community/elasticsearch_exporter/pkg/roundtripper" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/common/version" - "gopkg.in/alecthomas/kingpin.v2" + "github.com/prometheus/exporter-toolkit/web" + webflag "github.com/prometheus/exporter-toolkit/web/kingpinflag" ) const name = "elasticsearch_exporter" @@ -46,13 +49,11 @@ func (t *transportWithAPIKey) RoundTrip(req *http.Request) (*http.Response, erro func main() { var ( - listenAddress = kingpin.Flag("web.listen-address", - "Address to listen on for web interface and telemetry."). - Default(":9114").String() metricsPath = kingpin.Flag("web.telemetry-path", "Path under which to expose metrics."). Default("/metrics").String() - esURI = kingpin.Flag("es.uri", + toolkitFlags = webflag.AddFlags(kingpin.CommandLine, ":9114") + esURI = kingpin.Flag("es.uri", "HTTP API address of an Elasticsearch node."). Default("http://localhost:9200").String() esTimeout = kingpin.Flag("es.timeout", @@ -73,8 +74,11 @@ func main() { esExportIndicesMappings = kingpin.Flag("es.indices_mappings", "Export stats for mappings of all indices of the cluster."). Default("false").Bool() - esExportClusterSettings = kingpin.Flag("es.cluster_settings", - "Export stats for cluster settings."). + esExportIndexAliases = kingpin.Flag("es.aliases", + "Export informational alias metrics."). + Default("true").Bool() + esExportILM = kingpin.Flag("es.ilm", + "Export index lifecycle politics for indices in the cluster."). Default("false").Bool() esExportShards = kingpin.Flag("es.shards", "Export stats for shards in the cluster (implies --es.indices)."). @@ -85,6 +89,12 @@ func main() { esExportSLM = kingpin.Flag("es.slm", "Export stats for SLM snapshots."). Default("false").Bool() + esIndicesFilter = kingpin.Flag("es.indices_filter", + "Indices filter by name for which metrics should be exposed, using prefix with wildcards and/or commas as multi-selection delimiter."). + Default("_all").String() + esExportDataStream = kingpin.Flag("es.data_stream", + "Export stas for Data Streams."). + Default("false").Bool() esClusterInfoInterval = kingpin.Flag("es.clusterinfo.interval", "Cluster info update interval for the cluster label"). Default("5m").Duration() @@ -109,6 +119,12 @@ func main() { logOutput = kingpin.Flag("log.output", "Sets the log output. Valid outputs are stdout and stderr"). Default("stdout").String() + awsRegion = kingpin.Flag("aws.region", + "Region for AWS elasticsearch"). + Default("").String() + awsRoleArn = kingpin.Flag("aws.role-arn", + "Role ARN of an IAM role to assume."). + Default("").String() ) kingpin.Version(version.Print(name)) @@ -119,7 +135,7 @@ func main() { esURL, err := url.Parse(*esURI) if err != nil { - _ = level.Error(logger).Log( + level.Error(logger).Log( "msg", "failed to parse es.uri", "err", err, ) @@ -157,6 +173,14 @@ func main() { Transport: httpTransport, } + if *awsRegion != "" { + httpClient.Transport, err = roundtripper.NewAWSSigningTransport(httpTransport, *awsRegion, *awsRoleArn, logger) + if err != nil { + level.Error(logger).Log("msg", "failed to create AWS transport", "err", err) + os.Exit(1) + } + } + // version metric prometheus.MustRegister(version.NewCollector(name)) @@ -168,7 +192,7 @@ func main() { collector.WithHTTPClient(httpClient), ) if err != nil { - _ = level.Error(logger).Log("msg", "failed to create Elasticsearch collector", "err", err) + level.Error(logger).Log("msg", "failed to create Elasticsearch collector", "err", err) os.Exit(1) } prometheus.MustRegister(exporter) @@ -182,10 +206,10 @@ func main() { if *esExportIndices || *esExportShards { prometheus.MustRegister(collector.NewShards(logger, httpClient, esURL)) - iC := collector.NewIndices(logger, httpClient, esURL, *esExportShards) + iC := collector.NewIndices(logger, httpClient, esURL, *esExportShards, *esExportIndexAliases, *esIndicesFilter) prometheus.MustRegister(iC) if registerErr := clusterInfoRetriever.RegisterConsumer(iC); registerErr != nil { - _ = level.Error(logger).Log("msg", "failed to register indices collector in cluster info") + level.Error(logger).Log("msg", "failed to register indices collector in cluster info") os.Exit(1) } } @@ -198,20 +222,22 @@ func main() { prometheus.MustRegister(collector.NewSLM(logger, httpClient, esURL)) } - if *esExportClusterSettings { - prometheus.MustRegister(collector.NewClusterSettings(logger, httpClient, esURL)) + if *esExportDataStream { + prometheus.MustRegister(collector.NewDataStream(logger, httpClient, esURL)) } if *esExportIndicesSettings { - prometheus.MustRegister(collector.NewIndicesSettings(logger, httpClient, esURL)) + prometheus.MustRegister(collector.NewIndicesSettings(logger, httpClient, esURL, *esIndicesFilter)) } if *esExportIndicesMappings { - prometheus.MustRegister(collector.NewIndicesMappings(logger, httpClient, esURL)) + prometheus.MustRegister(collector.NewIndicesMappings(logger, httpClient, esURL, *esIndicesFilter)) } - // create a http server - server := &http.Server{} + if *esExportILM { + prometheus.MustRegister(collector.NewIlmStatus(logger, httpClient, esURL)) + prometheus.MustRegister(collector.NewIlmIndicies(logger, httpClient, esURL)) + } // Create a context that is cancelled on SIGKILL or SIGINT. ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, os.Kill) @@ -220,63 +246,56 @@ func main() { // start the cluster info retriever switch runErr := clusterInfoRetriever.Run(ctx); runErr { case nil: - _ = level.Info(logger).Log( + level.Info(logger).Log( "msg", "started cluster info retriever", "interval", (*esClusterInfoInterval).String(), ) case clusterinfo.ErrInitialCallTimeout: - _ = level.Info(logger).Log("msg", "initial cluster info call timed out") + level.Info(logger).Log("msg", "initial cluster info call timed out") default: - _ = level.Error(logger).Log("msg", "failed to run cluster info retriever", "err", err) + level.Error(logger).Log("msg", "failed to run cluster info retriever", "err", err) os.Exit(1) } // register cluster info retriever as prometheus collector prometheus.MustRegister(clusterInfoRetriever) - mux := http.DefaultServeMux - mux.Handle(*metricsPath, promhttp.Handler()) - mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - _, err = w.Write([]byte(` - Elasticsearch Exporter - -

Elasticsearch Exporter

-

Metrics

- - `)) + http.Handle(*metricsPath, promhttp.Handler()) + if *metricsPath != "/" && *metricsPath != "" { + landingConfig := web.LandingConfig{ + Name: "Elasticsearch Exporter", + Description: "Prometheus Exporter for Elasticsearch servers", + Version: version.Info(), + Links: []web.LandingLinks{ + { + Address: *metricsPath, + Text: "Metrics", + }, + }, + } + landingPage, err := web.NewLandingPage(landingConfig) if err != nil { - _ = level.Error(logger).Log( - "msg", "failed handling writer", - "err", err, - ) + level.Error(logger).Log("err", err) + os.Exit(1) } - }) + http.Handle("/", landingPage) + } // health endpoint - mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) { + http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) { http.Error(w, http.StatusText(http.StatusOK), http.StatusOK) }) - server.Handler = mux - server.Addr = *listenAddress - - _ = level.Info(logger).Log( - "msg", "starting elasticsearch_exporter", - "addr", *listenAddress, - ) - + server := &http.Server{} go func() { - if err := server.ListenAndServe(); err != nil { - _ = level.Error(logger).Log( - "msg", "http server quit", - "err", err, - ) + if err = web.ListenAndServe(server, toolkitFlags, logger); err != nil { + level.Error(logger).Log("msg", "http server quit", "err", err) os.Exit(1) } }() <-ctx.Done() - _ = level.Info(logger).Log("msg", "shutting down") + level.Info(logger).Log("msg", "shutting down") // create a context for graceful http server shutdown srvCtx, srvCancel := context.WithTimeout(context.Background(), 5*time.Second) defer srvCancel() diff --git a/pkg/clusterinfo/clusterinfo.go b/pkg/clusterinfo/clusterinfo.go index d7f2046b..00486f5f 100644 --- a/pkg/clusterinfo/clusterinfo.go +++ b/pkg/clusterinfo/clusterinfo.go @@ -18,7 +18,7 @@ import ( "encoding/json" "errors" "fmt" - "io/ioutil" + "io" "net/http" "net/url" "path" @@ -49,7 +49,7 @@ type consumer interface { String() string } -// Retriever periodically gets the cluster info from the / endpoint end +// Retriever periodically gets the cluster info from the / endpoint and // sends it to all registered consumer channels type Retriever struct { consumerChannels map[string]*chan *Response @@ -131,7 +131,7 @@ func (r *Retriever) updateMetrics(res *Response) { u := *r.url u.User = nil url := u.String() - _ = level.Debug(r.logger).Log("msg", "updating cluster info metrics") + level.Debug(r.logger).Log("msg", "updating cluster info metrics") // scrape failed, response is nil if res == nil { r.up.WithLabelValues(url).Set(0.0) @@ -146,7 +146,7 @@ func (r *Retriever) updateMetrics(res *Response) { res.Version.BuildHash, res.Version.Number.String(), res.Version.LuceneVersion.String(), - ) + ).Set(1.0) r.lastUpstreamSuccessTs.WithLabelValues(url).Set(float64(time.Now().Unix())) } @@ -174,18 +174,18 @@ func (r *Retriever) Run(ctx context.Context) error { for { select { case <-ctx.Done(): - _ = level.Info(r.logger).Log( + level.Info(r.logger).Log( "msg", "context cancelled, exiting cluster info update loop", "err", ctx.Err(), ) return case <-r.sync: - _ = level.Info(r.logger).Log( + level.Info(r.logger).Log( "msg", "providing consumers with updated cluster info label", ) res, err := r.fetchAndDecodeClusterInfo() if err != nil { - _ = level.Error(r.logger).Log( + level.Error(r.logger).Log( "msg", "failed to retrieve cluster info from ES", "err", err, ) @@ -194,7 +194,7 @@ func (r *Retriever) Run(ctx context.Context) error { } r.updateMetrics(res) for name, consumerCh := range r.consumerChannels { - _ = level.Debug(r.logger).Log( + level.Debug(r.logger).Log( "msg", "sending update", "consumer", name, "res", fmt.Sprintf("%+v", res), @@ -211,7 +211,7 @@ func (r *Retriever) Run(ctx context.Context) error { } }(ctx) // trigger initial cluster info call - _ = level.Info(r.logger).Log( + level.Info(r.logger).Log( "msg", "triggering initial cluster info call", ) r.sync <- struct{}{} @@ -219,7 +219,7 @@ func (r *Retriever) Run(ctx context.Context) error { // start a ticker routine go func(ctx context.Context) { if r.interval <= 0 { - _ = level.Info(r.logger).Log( + level.Info(r.logger).Log( "msg", "no periodic cluster info label update requested", ) return @@ -228,13 +228,13 @@ func (r *Retriever) Run(ctx context.Context) error { for { select { case <-ctx.Done(): - _ = level.Info(r.logger).Log( + level.Info(r.logger).Log( "msg", "context cancelled, exiting cluster info trigger loop", "err", ctx.Err(), ) return case <-ticker.C: - _ = level.Debug(r.logger).Log( + level.Debug(r.logger).Log( "msg", "triggering periodic update", ) r.sync <- struct{}{} @@ -246,7 +246,7 @@ func (r *Retriever) Run(ctx context.Context) error { select { case <-startupComplete: // first sync has been successful - _ = level.Debug(r.logger).Log("msg", "initial clusterinfo sync succeeded") + level.Debug(r.logger).Log("msg", "initial clusterinfo sync succeeded") return nil case <-time.After(initialTimeout): // initial call timed out @@ -264,7 +264,7 @@ func (r *Retriever) fetchAndDecodeClusterInfo() (*Response, error) { res, err := r.client.Get(u.String()) if err != nil { - _ = level.Error(r.logger).Log( + level.Error(r.logger).Log( "msg", "failed to get cluster info", "err", err, ) @@ -274,7 +274,7 @@ func (r *Retriever) fetchAndDecodeClusterInfo() (*Response, error) { defer func() { err = res.Body.Close() if err != nil { - _ = level.Warn(r.logger).Log( + level.Warn(r.logger).Log( "msg", "failed to close http.Client", "err", err, ) @@ -285,7 +285,7 @@ func (r *Retriever) fetchAndDecodeClusterInfo() (*Response, error) { return nil, fmt.Errorf("HTTP Request failed with code %d", res.StatusCode) } - bts, err := ioutil.ReadAll(res.Body) + bts, err := io.ReadAll(res.Body) if err != nil { return nil, err } diff --git a/pkg/clusterinfo/clusterinfo_response.go b/pkg/clusterinfo/clusterinfo_response.go index ccacb4ba..5e384f0c 100644 --- a/pkg/clusterinfo/clusterinfo_response.go +++ b/pkg/clusterinfo/clusterinfo_response.go @@ -14,7 +14,7 @@ package clusterinfo import ( - "github.com/blang/semver" + "github.com/blang/semver/v4" ) // Response is the cluster info retrievable from the / endpoint diff --git a/pkg/clusterinfo/clusterinfo_test.go b/pkg/clusterinfo/clusterinfo_test.go index 4bec8d3b..beb3ff6b 100644 --- a/pkg/clusterinfo/clusterinfo_test.go +++ b/pkg/clusterinfo/clusterinfo_test.go @@ -27,7 +27,7 @@ import ( "github.com/go-kit/log" - "github.com/blang/semver" + "github.com/blang/semver/v4" ) const ( diff --git a/pkg/roundtripper/roundtripper.go b/pkg/roundtripper/roundtripper.go new file mode 100644 index 00000000..4229f96d --- /dev/null +++ b/pkg/roundtripper/roundtripper.go @@ -0,0 +1,110 @@ +// Copyright 2022 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package roundtripper + +import ( + "bytes" + "context" + "crypto/sha256" + "encoding/hex" + "io" + "net/http" + "time" + + "github.com/aws/aws-sdk-go-v2/aws" + v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/credentials/stscreds" + "github.com/aws/aws-sdk-go-v2/service/sts" + "github.com/go-kit/log" + "github.com/go-kit/log/level" +) + +const ( + service = "es" +) + +type AWSSigningTransport struct { + t http.RoundTripper + creds aws.CredentialsProvider + region string + log log.Logger +} + +func NewAWSSigningTransport(transport http.RoundTripper, region string, roleArn string, log log.Logger) (*AWSSigningTransport, error) { + cfg, err := config.LoadDefaultConfig(context.Background(), config.WithRegion(region)) + if err != nil { + level.Error(log).Log("msg", "failed to load aws default config", "err", err) + return nil, err + } + + if roleArn != "" { + cfg.Credentials = stscreds.NewAssumeRoleProvider(sts.NewFromConfig(cfg), roleArn) + } + + creds := aws.NewCredentialsCache(cfg.Credentials) + // Run a single fetch credentials operation to ensure that the credentials + // are valid before returning the transport. + _, err = cfg.Credentials.Retrieve(context.Background()) + if err != nil { + level.Error(log).Log("msg", "failed to retrive aws credentials", "err", err) + return nil, err + } + + return &AWSSigningTransport{ + t: transport, + region: region, + creds: creds, + log: log, + }, err +} + +func (a *AWSSigningTransport) RoundTrip(req *http.Request) (*http.Response, error) { + signer := v4.NewSigner() + payloadHash, newReader, err := hashPayload(req.Body) + if err != nil { + level.Error(a.log).Log("msg", "failed to hash request body", "err", err) + return nil, err + } + req.Body = newReader + + creds, err := a.creds.Retrieve(context.Background()) + if err != nil { + level.Error(a.log).Log("msg", "failed to retrieve aws credentials", "err", err) + return nil, err + } + + err = signer.SignHTTP(context.Background(), creds, req, payloadHash, service, a.region, time.Now()) + if err != nil { + level.Error(a.log).Log("msg", "failed to sign request body", "err", err) + return nil, err + } + return a.t.RoundTrip(req) +} + +func hashPayload(r io.ReadCloser) (string, io.ReadCloser, error) { + var newReader io.ReadCloser + payload := []byte("") + if r != nil { + defer r.Close() + payload, err := io.ReadAll(r) + if err != nil { + return "", newReader, err + } + newReader = io.NopCloser(bytes.NewReader(payload)) + } + hash := sha256.Sum256(payload) + payloadHash := hex.EncodeToString(hash[:]) + return payloadHash, newReader, nil +} diff --git a/scripts/errcheck_excludes.txt b/scripts/errcheck_excludes.txt new file mode 100644 index 00000000..14b824f8 --- /dev/null +++ b/scripts/errcheck_excludes.txt @@ -0,0 +1,4 @@ +// Used in HTTP handlers, any error is handled by the server itself. +(net/http.ResponseWriter).Write +// Never check for logger errors. +(github.com/go-kit/log.Logger).Log diff --git a/tls.go b/tls.go index 025ea6d7..0631a409 100644 --- a/tls.go +++ b/tls.go @@ -16,8 +16,8 @@ package main import ( "crypto/tls" "crypto/x509" - "io/ioutil" "log" + "os" ) func createTLSConfig(pemFile, pemCertFile, pemPrivateKeyFile string, insecureSkipVerify bool) *tls.Config { @@ -51,7 +51,7 @@ func createTLSConfig(pemFile, pemCertFile, pemPrivateKeyFile string, insecureSki } func loadCertificatesFrom(pemFile string) (*x509.CertPool, error) { - caCert, err := ioutil.ReadFile(pemFile) + caCert, err := os.ReadFile(pemFile) if err != nil { return nil, err }