Compare commits

...

166 Commits

Author SHA1 Message Date
PrometheusBot
92b25a1eb0
Update common Prometheus files (#1135)
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2026-02-04 19:39:17 -05:00
PrometheusBot
5233bc8957
Update common Prometheus files (#1127)
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2026-01-31 22:40:18 -05:00
diydriller
5dfce351ec
Add Index-Level Indexing Metrics (#1125)
* Feat add indexing-related metrics

Signed-off-by: diydriller <dhrhd080@naver.com>

* Fix make IndexFailed and WriteLoad optional fields for version compatibility

Signed-off-by: diydriller <dhrhd080@naver.com>

* Test add tests for new indexing metrics

Signed-off-by: diydriller <dhrhd080@naver.com>

---------

Signed-off-by: diydriller <dhrhd080@naver.com>
2026-01-17 15:12:41 -05:00
dependabot[bot]
84ca898d8e
Bump actions/checkout from 5.0.0 to 6.0.1 (#1117)
Bumps [actions/checkout](https://github.com/actions/checkout) from 5.0.0 to 6.0.1.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v5...8e8c483db84b4bee98b60c0593521ed34d9990e8)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 6.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-10 13:54:17 -05:00
dependabot[bot]
348b806bda
Bump prometheus/promci from 0.4.7 to 0.5.3 (#1116)
Bumps [prometheus/promci](https://github.com/prometheus/promci) from 0.4.7 to 0.5.3.
- [Release notes](https://github.com/prometheus/promci/releases)
- [Commits](443c7fc239...c0916f0a41)

---
updated-dependencies:
- dependency-name: prometheus/promci
  dependency-version: 0.5.3
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-10 13:50:06 -05:00
PrometheusBot
f57d9b6b5b
Update common Prometheus files (#1121)
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2026-01-10 13:28:56 -05:00
Ben Kochie
9469a6d617
Merge pull request #1118 from prometheus-community/dependabot/github_actions/actions/setup-go-6.1.0
Bump actions/setup-go from 6.0.0 to 6.1.0
2026-01-05 09:20:06 +01:00
Ben Kochie
fa338d24ce
Merge pull request #1115 from prometheus-community/dependabot/go_modules/aws-66135f5676
Bump the aws group with 4 updates
2026-01-05 09:03:50 +01:00
Ben Kochie
1b970de07b
Merge pull request #1120 from prometheus-community/repo_sync
Synchronize common files from prometheus/prometheus
2026-01-05 09:03:14 +01:00
prombot
1ea8dddf33 Update common Prometheus files
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2026-01-04 17:49:12 +00:00
dependabot[bot]
de34ae3d01
Bump actions/setup-go from 6.0.0 to 6.1.0
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 6.0.0 to 6.1.0.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v6...4dc6199c7b1a012772edbd06daecab0f50c9053c)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-version: 6.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-01-01 14:19:28 +00:00
dependabot[bot]
02c5a3e6d9
Bump the aws group with 4 updates
Bumps the aws group with 4 updates: [github.com/aws/aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2), [github.com/aws/aws-sdk-go-v2/config](https://github.com/aws/aws-sdk-go-v2), [github.com/aws/aws-sdk-go-v2/credentials](https://github.com/aws/aws-sdk-go-v2) and [github.com/aws/aws-sdk-go-v2/service/sts](https://github.com/aws/aws-sdk-go-v2).


Updates `github.com/aws/aws-sdk-go-v2` from 1.40.0 to 1.41.0
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/v1.40.0...v1.41.0)

Updates `github.com/aws/aws-sdk-go-v2/config` from 1.32.2 to 1.32.6
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/v1.32.2...v1.32.6)

Updates `github.com/aws/aws-sdk-go-v2/credentials` from 1.19.2 to 1.19.6
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/service/m2/v1.19.2...service/m2/v1.19.6)

Updates `github.com/aws/aws-sdk-go-v2/service/sts` from 1.41.2 to 1.41.5
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/service/ivs/v1.41.2...service/sts/v1.41.5)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2
  dependency-version: 1.41.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: aws
- dependency-name: github.com/aws/aws-sdk-go-v2/config
  dependency-version: 1.32.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: aws
- dependency-name: github.com/aws/aws-sdk-go-v2/credentials
  dependency-version: 1.19.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: aws
- dependency-name: github.com/aws/aws-sdk-go-v2/service/sts
  dependency-version: 1.41.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: aws
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-01-01 14:06:22 +00:00
PrometheusBot
cdc4b01705
Update common Prometheus files (#1114)
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2025-12-22 21:48:33 -05:00
Yuri Tsuprun
1ec2242bca
fix(collector): adding 'node' to defaultRoleLabels (#1111)
feat(collector): using nodeID in metric labels for better uniqueness

Signed-off-by: pincher95 <yuri.tsuprun@gmail.com>
Signed-off-by: pincher95 <yuri.tsuprun@logz.io>
2025-12-08 21:38:24 -05:00
PrometheusBot
eee51ae24a
Update common Prometheus files (#1113)
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2025-12-08 15:06:03 -05:00
Joe Adams
d74274fa19
Prep for v1.10 release (#1108)
* Perp for v1.10 release

- Bump VERSION
- Add Changelog
- Update dependencies

Signed-off-by: Joe Adams <github@joeadams.io>

* Update CHANGELOG.md

Co-authored-by: Ben Kochie <superq@gmail.com>
Signed-off-by: Joe Adams <github@joeadams.io>

---------

Signed-off-by: Joe Adams <github@joeadams.io>
Co-authored-by: Ben Kochie <superq@gmail.com>
2025-12-08 10:35:48 -05:00
Ben Kochie
d20e394771
Merge pull request #1097 from prometheus-community/repo_sync
Synchronize common files from prometheus/prometheus
2025-12-08 07:20:36 -08:00
dependabot[bot]
f1fda6818f
Bump golang.org/x/crypto from 0.43.0 to 0.45.0 (#1096)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.43.0 to 0.45.0.
- [Commits](https://github.com/golang/crypto/compare/v0.43.0...v0.45.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-version: 0.45.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-01 22:08:41 -05:00
prombot
df28d5921f Update common Prometheus files
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2025-11-20 17:50:37 +00:00
Ben Kochie
279ba21db4
Refactor README (#1095)
Move the metrics list to a separate markdown file to reduce the README
size below the 25k bytes limit of Dockerhub.

Signed-off-by: SuperQ <superq@gmail.com>
2025-11-19 09:33:22 -05:00
Ben Kochie
110a885c66
Merge pull request #1093 from sysadmind/readme-v110
Fix release version for config.file
2025-11-19 12:24:06 +01:00
Ben Kochie
aca930544c
Merge pull request #1094 from prometheus-community/repo_sync
Synchronize common files from prometheus/prometheus
2025-11-18 13:03:01 +01:00
prombot
c9fe3d448c Update common Prometheus files
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2025-11-05 17:49:15 +00:00
dependabot[bot]
36aba75c33
Bump golangci/golangci-lint-action from 7.0.0 to 8.0.0 (#1042)
Bumps [golangci/golangci-lint-action](https://github.com/golangci/golangci-lint-action) from 7.0.0 to 8.0.0.
- [Release notes](https://github.com/golangci/golangci-lint-action/releases)
- [Commits](1481404843...4afd733a84)

---
updated-dependencies:
- dependency-name: golangci/golangci-lint-action
  dependency-version: 8.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-04 21:17:24 -05:00
Joe Adams
8b66ebdc44
Fix release version for config.file
Signed-off-by: Joe Adams <github@joeadams.io>
2025-11-04 21:10:04 -05:00
dependabot[bot]
a4f9120aff
Bump the aws group with 4 updates (#1090)
Bumps the aws group with 4 updates: [github.com/aws/aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2), [github.com/aws/aws-sdk-go-v2/config](https://github.com/aws/aws-sdk-go-v2), [github.com/aws/aws-sdk-go-v2/credentials](https://github.com/aws/aws-sdk-go-v2) and [github.com/aws/aws-sdk-go-v2/service/sts](https://github.com/aws/aws-sdk-go-v2).


Updates `github.com/aws/aws-sdk-go-v2` from 1.39.2 to 1.39.5
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/v1.39.2...v1.39.5)

Updates `github.com/aws/aws-sdk-go-v2/config` from 1.31.12 to 1.31.16
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/config/v1.31.12...config/v1.31.16)

Updates `github.com/aws/aws-sdk-go-v2/credentials` from 1.18.16 to 1.18.20
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/config/v1.18.20/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/config/v1.18.16...config/v1.18.20)

Updates `github.com/aws/aws-sdk-go-v2/service/sts` from 1.38.6 to 1.39.0
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/service/sts/v1.38.6...v1.39.0)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2
  dependency-version: 1.39.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: aws
- dependency-name: github.com/aws/aws-sdk-go-v2/config
  dependency-version: 1.31.16
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: aws
- dependency-name: github.com/aws/aws-sdk-go-v2/credentials
  dependency-version: 1.18.20
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: aws
- dependency-name: github.com/aws/aws-sdk-go-v2/service/sts
  dependency-version: 1.39.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: aws
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-04 21:00:19 -05:00
dependabot[bot]
1bb240e13e
Bump github.com/prometheus/common from 0.67.1 to 0.67.2 (#1091)
Bumps [github.com/prometheus/common](https://github.com/prometheus/common) from 0.67.1 to 0.67.2.
- [Release notes](https://github.com/prometheus/common/releases)
- [Changelog](https://github.com/prometheus/common/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/common/compare/v0.67.1...v0.67.2)

---
updated-dependencies:
- dependency-name: github.com/prometheus/common
  dependency-version: 0.67.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-04 20:59:47 -05:00
Ben Kochie
56914a1d8b
Don't log collector errors (#1050)
Avoid logging collector failures at Error level to avoid log spam.

Signed-off-by: SuperQ <superq@gmail.com>
2025-10-28 07:08:08 -04:00
Ben Kochie
bdfeeffc09
Merge pull request #1089 from prometheus-community/repo_sync
Synchronize common files from prometheus/prometheus
2025-10-28 08:11:52 +01:00
Joe Adams
325e7dd61f
Fix mixed value types for disk watermark (#1055)
* Fix mixed value types for disk watermark

The disk watermark values can be a ratio or percentage according to the docs[1], however when set to a percentage, the defaults become an object and therefore fails to parse. In that case, we really only care about what the user set. Adds a test to confirm a fix for #1044.

Fixes #1044

[1] https://www.elastic.co/docs/reference/elasticsearch/configuration-reference/cluster-level-shard-allocation-routing-settings#disk-based-shard-allocation

Signed-off-by: Joe Adams <github@joeadams.io>

* Add missing test fixture

Signed-off-by: Joe Adams <github@joeadams.io>

---------

Signed-off-by: Joe Adams <github@joeadams.io>
2025-10-27 21:12:26 -04:00
prombot
7131333ce7 Update common Prometheus files
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2025-10-24 17:49:15 +00:00
Ben Kochie
91008f4902
Update Go (#1088)
* Update minimum Go version to 1.24.0.
* Update build to Go 1.25.
* Cleanup disabled CircleCI pipeline.

Signed-off-by: SuperQ <superq@gmail.com>
2025-10-24 07:09:27 -04:00
Ben Kochie
88c8fb6d31
Merge pull request #1082 from prometheus-community/dependabot/go_modules/github.com/prometheus/common-0.66.1
Bump github.com/prometheus/common from 0.65.0 to 0.66.1
2025-10-24 08:22:57 +02:00
dependabot[bot]
1cd5ffe190
Bump github.com/prometheus/common from 0.65.0 to 0.66.1
Bumps [github.com/prometheus/common](https://github.com/prometheus/common) from 0.65.0 to 0.66.1.
- [Release notes](https://github.com/prometheus/common/releases)
- [Changelog](https://github.com/prometheus/common/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/common/compare/v0.65.0...v0.66.1)

---
updated-dependencies:
- dependency-name: github.com/prometheus/common
  dependency-version: 0.66.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-24 06:17:08 +00:00
Ben Kochie
a04a789c0d
Merge pull request #1083 from prometheus-community/dependabot/go_modules/github.com/prometheus/exporter-toolkit-0.14.1
Bump github.com/prometheus/exporter-toolkit from 0.14.0 to 0.14.1
2025-10-24 08:14:53 +02:00
Ben Kochie
078972dba4
Merge pull request #1051 from sysadmind/rm-unsanitized-url
Do not log input URL string
2025-10-24 08:14:40 +02:00
dependabot[bot]
1f8b5ad641
Bump github.com/prometheus/exporter-toolkit from 0.14.0 to 0.14.1
Bumps [github.com/prometheus/exporter-toolkit](https://github.com/prometheus/exporter-toolkit) from 0.14.0 to 0.14.1.
- [Release notes](https://github.com/prometheus/exporter-toolkit/releases)
- [Commits](https://github.com/prometheus/exporter-toolkit/compare/v0.14.0...v0.14.1)

---
updated-dependencies:
- dependency-name: github.com/prometheus/exporter-toolkit
  dependency-version: 0.14.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-24 01:52:59 +00:00
dependabot[bot]
dbe29fedec
Bump github.com/prometheus/client_golang from 1.23.0 to 1.23.2 (#1084)
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.23.0 to 1.23.2.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.23.0...v1.23.2)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-version: 1.23.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-23 21:51:52 -04:00
dependabot[bot]
90bc1111dd
Bump actions/checkout from 4.2.2 to 5.0.0 (#1085)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4.2.2 to 5.0.0.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](11bd71901b...08c6903cd8)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 5.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-23 21:48:22 -04:00
dependabot[bot]
6d25270625
Bump the aws group with 4 updates (#1081)
Bumps the aws group with 4 updates: [github.com/aws/aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2), [github.com/aws/aws-sdk-go-v2/config](https://github.com/aws/aws-sdk-go-v2), [github.com/aws/aws-sdk-go-v2/credentials](https://github.com/aws/aws-sdk-go-v2) and [github.com/aws/aws-sdk-go-v2/service/sts](https://github.com/aws/aws-sdk-go-v2).


Updates `github.com/aws/aws-sdk-go-v2` from 1.37.2 to 1.39.2
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/v1.37.2...v1.39.2)

Updates `github.com/aws/aws-sdk-go-v2/config` from 1.30.3 to 1.31.12
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/v1.30.3...config/v1.31.12)

Updates `github.com/aws/aws-sdk-go-v2/credentials` from 1.18.3 to 1.18.16
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/config/v1.18.3...config/v1.18.16)

Updates `github.com/aws/aws-sdk-go-v2/service/sts` from 1.36.0 to 1.38.6
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/v1.36.0...service/sts/v1.38.6)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2
  dependency-version: 1.39.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: aws
- dependency-name: github.com/aws/aws-sdk-go-v2/config
  dependency-version: 1.31.12
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: aws
- dependency-name: github.com/aws/aws-sdk-go-v2/credentials
  dependency-version: 1.18.16
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: aws
- dependency-name: github.com/aws/aws-sdk-go-v2/service/sts
  dependency-version: 1.38.6
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: aws
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-23 21:45:38 -04:00
dependabot[bot]
1bb4b5823e
Bump actions/setup-go from 5.4.0 to 6.0.0 (#1086)
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 5.4.0 to 6.0.0.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](0aaccfd150...4469467582)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-version: 6.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-23 21:42:24 -04:00
Yuri Tsuprun
ca4c3133e5
Add multi-target support (#1063)
* Add multi-target support

Signed-off-by: pincher95 <yuri.tsuprun@logz.io>

* Update example-prometheus.yml

Signed-off-by: pincher95 <yuri.tsuprun@logz.io>

* Make `es.uri` optional by setting default to empty string check if it's empty and if so, don't parse it
Signed-off-by: pincher95 <yuri.tsuprun@logz.io>

Signed-off-by: pincher95 <yuri.tsuprun@logz.io>

* Update README.md

Signed-off-by: pincher95 <yuri.tsuprun@logz.io>

* Add sanity target scheme validation

Signed-off-by: pincher95 <yuri.tsuprun@logz.io>

* Change yaml package to go.yaml.in/yaml/v3

Signed-off-by: pincher95 <yuri.tsuprun@logz.io>

* Update yaml package to go.yaml.in/yaml/v3

Signed-off-by: pincher95 <yuri.tsuprun@logz.io>

* Update CHANGELOG.md

Signed-off-by: pincher95 <yuri.tsuprun@logz.io>

* Remove whitespaces from README.md

Signed-off-by: pincher95 <yuri.tsuprun@logz.io>

* Add testing for apikey authentication module
Update examples/auth_modules.yml
Fix main.go to apply userpass credentials only if the module type is explicitly set to userpass.

Signed-off-by: pincher95 <yuri.tsuprun@logz.io>

* Add Load-time validation for the auth module config file during startup
Keep light-weight validation for the probe params during runtime
Add AWS SigV4 authentication module support

Signed-off-by: pincher95 <yuri.tsuprun@logz.io>

* Expose error in the logger

Signed-off-by: pincher95 <yuri.tsuprun@logz.io>

* Add TLS config per target support
Add TLS config validation
Update config test to include TLS config

Signed-off-by: pincher95 <yuri.tsuprun@logz.io>

* Indices and Shards collectors now fetch cluster_name once from GET / when no clusterinfo retriever is attached, avoiding the previous "unknown_cluster" label.

Signed-off-by: pincher95 <yuri.tsuprun@logz.io>

* Removed the special-case logic that redirected /metrics?target= requests to /probe.
Updated auth_modules.yml to include AWS SigV4 signing and mTLS support.

Signed-off-by: pincher95 <yuri.tsuprun@logz.io>

* Add license headers to all new files

Signed-off-by: pincher95 <yuri.tsuprun@logz.io>

* Fixes for relative paths in multi-target mode

Signed-off-by: pincher95 <yuri.tsuprun@logz.io>

* Bump github.com/prometheus/client_golang from 1.22.0 to 1.23.0 (#1065)

Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.22.0 to 1.23.0.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.22.0...v1.23.0)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-version: 1.23.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: pincher95 <yuri.tsuprun@logz.io>

* Add target schema validation, http/https only
Add tls auth type support in multi-target mode
Update README.md, examples/auth_modules.yml, tests

Signed-off-by: pincher95 <yuri.tsuprun@logz.io>

* Cleanup

Signed-off-by: pincher95 <yuri.tsuprun@logz.io>

* Fix tls auth type validation

Signed-off-by: pincher95 <yuri.tsuprun@logz.io>

* Remove aws.region validation

Signed-off-by: pincher95 <yuri.tsuprun@logz.io>

* Add temp file cleanup in config_test.go

Signed-off-by: pincher95 <yuri.tsuprun@logz.io>

* Add copyright header to config_test.go

Signed-off-by: pincher95 <yuri.tsuprun@logz.io>

* Add version metric to the per-probe registry
Update roundtripper.go to use region from config or environment resolver if not provided in config file (AWS_REGION)
Update probe.go to accept module even if region omitted; environment resolver can provide it
Update config.go to use region as optional field
Update main.go to use region from config or environment resolver if not provided in config file (AWS_REGION) and update roundtripper.go to use region from config or environment resolver if not provided in config file (AWS_REGION)

Signed-off-by: pincher95 <yuri.tsuprun@logz.io>

---------

Signed-off-by: pincher95 <yuri.tsuprun@logz.io>
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Yuri Tsuprun <51751791+pincher95@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-18 21:43:53 -04:00
dependabot[bot]
5ceff33669
Bump the aws group with 4 updates (#1064)
Bumps the aws group with 4 updates: [github.com/aws/aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2), [github.com/aws/aws-sdk-go-v2/config](https://github.com/aws/aws-sdk-go-v2), [github.com/aws/aws-sdk-go-v2/credentials](https://github.com/aws/aws-sdk-go-v2) and [github.com/aws/aws-sdk-go-v2/service/sts](https://github.com/aws/aws-sdk-go-v2).


Updates `github.com/aws/aws-sdk-go-v2` from 1.36.5 to 1.37.1
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/v1.36.5...v1.37.1)

Updates `github.com/aws/aws-sdk-go-v2/config` from 1.29.17 to 1.30.2
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/config/v1.29.17...v1.30.2)

Updates `github.com/aws/aws-sdk-go-v2/credentials` from 1.17.70 to 1.18.2
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/config/v1.18.2/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/credentials/v1.17.70...config/v1.18.2)

Updates `github.com/aws/aws-sdk-go-v2/service/sts` from 1.34.0 to 1.35.1
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/v1.34.0...service/iam/v1.35.1)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2
  dependency-version: 1.37.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: aws
- dependency-name: github.com/aws/aws-sdk-go-v2/config
  dependency-version: 1.30.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: aws
- dependency-name: github.com/aws/aws-sdk-go-v2/credentials
  dependency-version: 1.18.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: aws
- dependency-name: github.com/aws/aws-sdk-go-v2/service/sts
  dependency-version: 1.35.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: aws
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-12 22:33:36 -04:00
dependabot[bot]
2c91a658f4
Bump github.com/prometheus/client_golang from 1.22.0 to 1.23.0 (#1065)
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.22.0 to 1.23.0.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.22.0...v1.23.0)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-version: 1.23.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-04 22:05:43 -04:00
PrometheusBot
c463acc8a6
Update common Prometheus files (#1059)
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2025-07-14 21:25:47 -04:00
dependabot[bot]
b3e2aaa8bc
Bump the aws group with 4 updates (#1056)
Bumps the aws group with 4 updates: [github.com/aws/aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2), [github.com/aws/aws-sdk-go-v2/config](https://github.com/aws/aws-sdk-go-v2), [github.com/aws/aws-sdk-go-v2/credentials](https://github.com/aws/aws-sdk-go-v2) and [github.com/aws/aws-sdk-go-v2/service/sts](https://github.com/aws/aws-sdk-go-v2).


Updates `github.com/aws/aws-sdk-go-v2` from 1.36.3 to 1.36.5
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/v1.36.3...v1.36.5)

Updates `github.com/aws/aws-sdk-go-v2/config` from 1.29.14 to 1.29.17
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/config/v1.29.14...config/v1.29.17)

Updates `github.com/aws/aws-sdk-go-v2/credentials` from 1.17.67 to 1.17.70
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/credentials/v1.17.67...credentials/v1.17.70)

Updates `github.com/aws/aws-sdk-go-v2/service/sts` from 1.33.19 to 1.34.0
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/service/sns/v1.33.19...v1.34.0)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2
  dependency-version: 1.36.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: aws
- dependency-name: github.com/aws/aws-sdk-go-v2/config
  dependency-version: 1.29.17
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: aws
- dependency-name: github.com/aws/aws-sdk-go-v2/credentials
  dependency-version: 1.17.70
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: aws
- dependency-name: github.com/aws/aws-sdk-go-v2/service/sts
  dependency-version: 1.34.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: aws
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-01 12:59:21 -04:00
dependabot[bot]
33661b982b
Bump github.com/prometheus/common from 0.63.0 to 0.65.0 (#1057)
Bumps [github.com/prometheus/common](https://github.com/prometheus/common) from 0.63.0 to 0.65.0.
- [Release notes](https://github.com/prometheus/common/releases)
- [Changelog](https://github.com/prometheus/common/blob/main/RELEASE.md)
- [Commits](https://github.com/prometheus/common/compare/v0.63.0...v0.65.0)

---
updated-dependencies:
- dependency-name: github.com/prometheus/common
  dependency-version: 0.65.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-01 10:47:00 -04:00
PrometheusBot
60f9e0c8e5
Update common Prometheus files (#1053)
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2025-06-18 14:02:43 -04:00
Joe Adams
00dfe058f4
Remove copyright dates (#1027)
This should help when PRs are open through a year change. These dates aren't necessary and the CNCF does not recommend keeping them.

https://github.com/cncf/foundation/blob/main/copyright-notices.md

Signed-off-by: Joe Adams <github@joeadams.io>
2025-06-17 21:11:22 -04:00
YenchangChan
8a1d851bdb
Fix memleak for create a TimeTicker without stop (#1049)
Signed-off-by: YenchangChan <chenyanchang1990@163.com>
2025-06-17 21:10:04 -04:00
Joe Adams
abac1b96e7 Do not log input URL string
The error itself already has the sanitized URL so there is no need to log the sensitive input string.

Signed-off-by: Joe Adams <github@joeadams.io>
2025-06-12 13:21:14 -04:00
Joe Adams
46721e114b
Add pprof for profiling (#1033)
* Add pprof for profiling

We have received reports of excessive memory usage for the exporter. Pprof provides a mechanism for users to dump the heap which should provide useful information about what memory has been allocated.

Signed-off-by: Joe Adams <github@joeadams.io>

* Update main.go

Co-authored-by: Ben Kochie <superq@gmail.com>
Signed-off-by: Joe Adams <github@joeadams.io>

---------

Signed-off-by: Joe Adams <github@joeadams.io>
Co-authored-by: Ben Kochie <superq@gmail.com>
2025-05-06 22:25:07 -04:00
Joe Adams
4a54705614
Update golangci-lint config for v2 (#1034)
This brings the common files in line with other prometheus repos. Most of these settings are coppied from prometheus/prometheus. Where it was a small change, I have enabled the new linte
rs and made the fixes. The remaining linters that are commented out deserve to be enabled and the fixes applied as independent changes.

Signed-off-by: Joe Adams <github@joeadams.io>
2025-05-06 22:22:12 -04:00
dependabot[bot]
25c76faf3a
Bump the aws group with 3 updates (#1035)
Bumps the aws group with 3 updates: [github.com/aws/aws-sdk-go-v2/config](https://github.com/aws/aws-sdk-go-v2), [github.com/aws/aws-sdk-go-v2/credentials](https://github.com/aws/aws-sdk-go-v2) and [github.com/aws/aws-sdk-go-v2/service/sts](https://github.com/aws/aws-sdk-go-v2).


Updates `github.com/aws/aws-sdk-go-v2/config` from 1.29.12 to 1.29.14
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/config/v1.29.12...config/v1.29.14)

Updates `github.com/aws/aws-sdk-go-v2/credentials` from 1.17.65 to 1.17.67
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/credentials/v1.17.65...credentials/v1.17.67)

Updates `github.com/aws/aws-sdk-go-v2/service/sts` from 1.33.17 to 1.33.19
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/service/sns/v1.33.17...service/sns/v1.33.19)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2/config
  dependency-version: 1.29.14
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: aws
- dependency-name: github.com/aws/aws-sdk-go-v2/credentials
  dependency-version: 1.17.67
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: aws
- dependency-name: github.com/aws/aws-sdk-go-v2/service/sts
  dependency-version: 1.33.19
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: aws
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-06 22:20:00 -04:00
dependabot[bot]
80a0be6a4b
Bump github.com/prometheus/client_golang from 1.21.1 to 1.22.0 (#1036)
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.21.1 to 1.22.0.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.21.1...v1.22.0)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-version: 1.22.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-06 22:15:37 -04:00
dependabot[bot]
2645c58e90
Bump golang.org/x/net from 0.36.0 to 0.38.0 (#1032)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.36.0 to 0.38.0.
- [Commits](https://github.com/golang/net/compare/v0.36.0...v0.38.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-version: 0.38.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-22 21:25:49 -04:00
Ben Kochie
8f67121f0b
Merge pull request #1029 from sysadmind/opensearch-readme
Update README for version compatibility
2025-04-05 17:59:41 +01:00
Joe Adams
78c2672b04
Update README for version compatibility
Add OpenSearch as a compatible version that is supported by the exporter. Also remove maintainers section from README as this is already covered in the MAINTAINERS.md file.

Signed-off-by: Joe Adams <github@joeadams.io>
2025-04-03 22:24:12 -04:00
Richard Klose
08636845fe
feat: add support for _health_report (#1002)
* feat: add support for _health_report

In elasticsearch 8.7 a new endpoint for cluster health has been added. See https://www.elastic.co/docs/api/doc/elasticsearch/v8/operation/operation-health-report

Signed-off-by: Richard Klose <richard.klose@wiit.cloud>

* docs: update cardinality in README and release version

Co-authored-by: Joe Adams <github@joeadams.io>
Signed-off-by: Richard Klose <richard@klose.dev>

---------

Signed-off-by: Richard Klose <richard.klose@wiit.cloud>
Signed-off-by: Richard Klose <richard@klose.dev>
Co-authored-by: Joe Adams <github@joeadams.io>
2025-04-01 21:58:28 -04:00
dependabot[bot]
ff2a9185ed
Bump the aws group with 3 updates (#1021)
Bumps the aws group with 3 updates: [github.com/aws/aws-sdk-go-v2/config](https://github.com/aws/aws-sdk-go-v2), [github.com/aws/aws-sdk-go-v2/credentials](https://github.com/aws/aws-sdk-go-v2) and [github.com/aws/aws-sdk-go-v2/service/sts](https://github.com/aws/aws-sdk-go-v2).


Updates `github.com/aws/aws-sdk-go-v2/config` from 1.29.8 to 1.29.12
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/config/v1.29.8...config/v1.29.12)

Updates `github.com/aws/aws-sdk-go-v2/credentials` from 1.17.61 to 1.17.65
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/credentials/v1.17.61...credentials/v1.17.65)

Updates `github.com/aws/aws-sdk-go-v2/service/sts` from 1.33.16 to 1.33.17
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/service/sns/v1.33.16...service/sns/v1.33.17)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2/config
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: aws
- dependency-name: github.com/aws/aws-sdk-go-v2/credentials
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: aws
- dependency-name: github.com/aws/aws-sdk-go-v2/service/sts
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: aws
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-01 21:49:25 -04:00
dependabot[bot]
3f41e5f9c0
Bump github.com/prometheus/client_golang from 1.21.0 to 1.21.1 (#1022)
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.21.0 to 1.21.1.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.21.0...v1.21.1)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-01 21:45:31 -04:00
dependabot[bot]
fee0e4dc40
Bump github.com/prometheus/common from 0.62.0 to 0.63.0 (#1023)
Bumps [github.com/prometheus/common](https://github.com/prometheus/common) from 0.62.0 to 0.63.0.
- [Release notes](https://github.com/prometheus/common/releases)
- [Changelog](https://github.com/prometheus/common/blob/main/RELEASE.md)
- [Commits](https://github.com/prometheus/common/compare/v0.62.0...v0.63.0)

---
updated-dependencies:
- dependency-name: github.com/prometheus/common
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-01 21:35:34 -04:00
dependabot[bot]
1799ebe922
Bump actions/setup-go from 5.3.0 to 5.4.0 (#1026)
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 5.3.0 to 5.4.0.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](f111f3307d...0aaccfd150)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-01 21:15:48 -04:00
dependabot[bot]
b6fd4be0cf
Bump prometheus/promci from 0.4.6 to 0.4.7 (#1024)
Bumps [prometheus/promci](https://github.com/prometheus/promci) from 0.4.6 to 0.4.7.
- [Release notes](https://github.com/prometheus/promci/releases)
- [Commits](c3c93a50d5...443c7fc239)

---
updated-dependencies:
- dependency-name: prometheus/promci
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-01 21:14:16 -04:00
dependabot[bot]
9dc402e2c1
Bump golangci/golangci-lint-action from 6.2.0 to 6.5.0 (#1012)
Bumps [golangci/golangci-lint-action](https://github.com/golangci/golangci-lint-action) from 6.2.0 to 6.5.0.
- [Release notes](https://github.com/golangci/golangci-lint-action/releases)
- [Commits](ec5d18412c...2226d7cb06)

---
updated-dependencies:
- dependency-name: golangci/golangci-lint-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-17 20:59:40 -04:00
PrometheusBot
36754ef9a3
Update common Prometheus files (#1017)
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2025-03-16 16:12:23 -04:00
dependabot[bot]
8afbc87e07
Bump golang.org/x/net from 0.33.0 to 0.36.0 (#1018)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.33.0 to 0.36.0.
- [Commits](https://github.com/golang/net/compare/v0.33.0...v0.36.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-16 16:11:49 -04:00
Ben Kochie
46f304de22
Merge pull request #1016 from sysadmind/golangcilint-cleanup
Remove unused golangci-lint config
2025-03-10 08:41:29 +01:00
Joe Adams
d6b75359fc
Refactor ILM collector (#999)
* Refactor ILM collector

Consolidate the ILM collector logic into a single collector using the new Collector interface

Signed-off-by: Joe Adams <github@joeadams.io>
2025-03-09 21:15:48 -04:00
Joe Adams
f0ae1957f4
Remove unused golangci-lint config
This config isn't needed because we're the code doesn't fail the linter check. The config is however preventing golangci-lint from being upgraded because this does not pass the schema validation.

Signed-off-by: Joe Adams <github@joeadams.io>
2025-03-09 21:09:28 -04:00
Joe Adams
fc9f42c4c8
Refactor data stream collector (#983)
- Move metric DESC to vars to aid in unused linter checks
- Use new Collector interface

Signed-off-by: Joe Adams <github@joeadams.io>
2025-03-09 21:08:28 -04:00
Joe Adams
4ab0f07290
Refactor indices collector (#1014)
-  Move metric DESC to vars to aid in unused linter checks
-  Clean up HTTP requests and JSON handling

Will refactor to use the Collector interface in a future change

Signed-off-by: Joe Adams <github@joeadams.io>
2025-03-09 21:03:11 -04:00
Joe Adams
e0de42975b
Refactor tests for indices settings (#982)
- Refactor tests to test the output of the collector
- Add missing metric descriptions in Describe()

Signed-off-by: Joe Adams <github@joeadams.io>
2025-03-09 20:47:43 -04:00
Ben Kochie
4301b8d655
Merge pull request #1003 from prometheus-community/superq/v1.9.0
Release v1.9.0
2025-03-03 10:59:06 +01:00
Ben Kochie
17f9f07e3d
Merge pull request #1013 from prometheus-community/dependabot/go_modules/aws-e4759fe239
Bump the aws group with 3 updates
2025-03-03 10:58:29 +01:00
dependabot[bot]
ea5a657777
Bump the aws group with 3 updates
Bumps the aws group with 3 updates: [github.com/aws/aws-sdk-go-v2/config](https://github.com/aws/aws-sdk-go-v2), [github.com/aws/aws-sdk-go-v2/credentials](https://github.com/aws/aws-sdk-go-v2) and [github.com/aws/aws-sdk-go-v2/service/sts](https://github.com/aws/aws-sdk-go-v2).


Updates `github.com/aws/aws-sdk-go-v2/config` from 1.29.6 to 1.29.8
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/config/v1.29.6...config/v1.29.8)

Updates `github.com/aws/aws-sdk-go-v2/credentials` from 1.17.59 to 1.17.61
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/credentials/v1.17.59...credentials/v1.17.61)

Updates `github.com/aws/aws-sdk-go-v2/service/sts` from 1.33.14 to 1.33.16
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/service/sns/v1.33.14...service/sns/v1.33.16)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2/config
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: aws
- dependency-name: github.com/aws/aws-sdk-go-v2/credentials
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: aws
- dependency-name: github.com/aws/aws-sdk-go-v2/service/sts
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: aws
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-03 09:54:32 +00:00
Ben Kochie
043dbe314a
Merge pull request #1011 from prometheus-community/superq/group_aws
Group AWS dependabot updates
2025-03-03 10:50:41 +01:00
Ben Kochie
f84d8b5d48
Merge pull request #1009 from sysadmind/indices-test
Add tests for Indices.shard
2025-03-03 10:50:28 +01:00
SuperQ
5e8e0c0baa
Group AWS dependabot updates
Reduce the montly PR updates by grouping the AWS Go modules.

Signed-off-by: SuperQ <superq@gmail.com>
2025-03-03 10:47:51 +01:00
Ben Kochie
6799cb5f84
Merge pull request #1010 from sysadmind/rm-circleci
Remove circleci config
2025-03-03 10:43:02 +01:00
Ben Kochie
e998563ec0
Merge pull request #1008 from prometheus-community/dependabot/go_modules/github.com/prometheus/client_golang-1.21.0
Bump github.com/prometheus/client_golang from 1.20.5 to 1.21.0
2025-03-03 10:42:20 +01:00
Ben Kochie
73b5e4615a
Merge pull request #1006 from prometheus-community/dependabot/go_modules/github.com/aws/aws-sdk-go-v2-1.36.3
Bump github.com/aws/aws-sdk-go-v2 from 1.36.1 to 1.36.3
2025-03-03 10:39:50 +01:00
Joe Adams
6f79acc690
Remove circleci config
We have moved to GitHub Actions, so disable CircleCI jobs. Will revisit removing this file in the future.

Signed-off-by: Joe Adams <github@joeadams.io>
2025-03-02 20:45:45 -05:00
Joe Adams
06975c8507
Add missing metric descriptions
Signed-off-by: Joe Adams <github@joeadams.io>
2025-03-02 20:35:21 -05:00
Joe Adams
6700e15bee
Add tests for Indices.shard
This code path was not perviously covered by tests. This adds a test case for the most recently tested version of elasticsearch with Indices.shard set to true.

Signed-off-by: Joe Adams <github@joeadams.io>
2025-03-02 20:31:11 -05:00
dependabot[bot]
98c791f3b1
Bump github.com/prometheus/client_golang from 1.20.5 to 1.21.0
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.20.5 to 1.21.0.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.20.5...v1.21.0)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-01 14:50:35 +00:00
dependabot[bot]
e4eefa0627
Bump github.com/aws/aws-sdk-go-v2 from 1.36.1 to 1.36.3
Bumps [github.com/aws/aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2) from 1.36.1 to 1.36.3.
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/v1.36.1...v1.36.3)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-01 14:49:53 +00:00
Joe Adams
7b794ff7b2
Fix github actions docker image org (#1000)
Actions are currently failing to publish the images because the image names are incorrect. I'm not positive if there are more changes necessary yet, but this should correct the organization name.

See https://github.com/prometheus-community/elasticsearch_exporter/actions/runs/13350556606/job/37286525153

Signed-off-by: Joe Adams <github@joeadams.io>
2025-02-27 20:52:10 -05:00
SuperQ
ea1dd11d4f
Release v1.9.0
BREAKING CHANGES:

The flag `--es.slm` has been renamed to `--collector.slm`.

The logging system has been replaced with log/slog from the stdlib. This change is being made across the prometheus ecosystem. The logging output has changed, but the messages and levels remain the same. The `ts` label for the timestamp has bewen replaced with `time`, the accuracy is less, and the timezone is not forced to UTC. The `caller` field has been replaced by the `source` field, which now includes the full path to the source file. The `level` field now exposes the log level in capital letters.

* [CHANGE] Rename --es.slm to --collector.slm #932
* [CHANGE] Replace logging system #942
* [ENHANCEMENT] Add external refresh stats #933

Signed-off-by: SuperQ <superq@gmail.com>
2025-02-26 18:56:31 +01:00
dependabot[bot]
05609ff593
Bump github.com/prometheus/exporter-toolkit from 0.13.1 to 0.14.0 (#1001)
Bumps [github.com/prometheus/exporter-toolkit](https://github.com/prometheus/exporter-toolkit) from 0.13.1 to 0.14.0.
- [Release notes](https://github.com/prometheus/exporter-toolkit/releases)
- [Changelog](https://github.com/prometheus/exporter-toolkit/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prometheus/exporter-toolkit/compare/v0.13.1...v0.14.0)

---
updated-dependencies:
- dependency-name: github.com/prometheus/exporter-toolkit
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-19 22:18:58 -05:00
PrometheusBot
6c221f72d9
Update common Prometheus files (#998)
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2025-02-19 22:03:24 -05:00
Sandhya
41561072de
Update main.go (#981)
Corrected the description in below lines

esExportDataStream = kingpin.Flag("es.data_stream",
			"Export stats for Data Streams.").

Signed-off-by: Sandhya <108527554+Sandhyaranitp@users.noreply.github.com>
2025-02-15 20:42:13 -05:00
PrometheusBot
ff87990e2a
Update common Prometheus files (#985)
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2025-02-15 20:38:36 -05:00
dependabot[bot]
2b71755dbf
Bump golang.org/x/net from 0.29.0 to 0.33.0 (#994)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.29.0 to 0.33.0.
- [Commits](https://github.com/golang/net/compare/v0.29.0...v0.33.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-15 13:01:50 -05:00
dependabot[bot]
5bc975f8d5
Bump github.com/aws/aws-sdk-go-v2/config from 1.28.7 to 1.29.6 (#995)
Bumps [github.com/aws/aws-sdk-go-v2/config](https://github.com/aws/aws-sdk-go-v2) from 1.28.7 to 1.29.6.
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/config/v1.28.7...config/v1.29.6)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2/config
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-15 13:00:28 -05:00
dependabot[bot]
23b43a85e4
Bump github.com/aws/aws-sdk-go-v2/credentials from 1.17.48 to 1.17.59 (#997)
Bumps [github.com/aws/aws-sdk-go-v2/credentials](https://github.com/aws/aws-sdk-go-v2) from 1.17.48 to 1.17.59.
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/credentials/v1.17.48...credentials/v1.17.59)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2/credentials
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-15 12:35:32 -05:00
dependabot[bot]
000290352e
Bump github.com/aws/aws-sdk-go-v2 from 1.32.7 to 1.36.0 (#992)
Bumps [github.com/aws/aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2) from 1.32.7 to 1.36.0.
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/v1.32.7...v1.36.0)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-15 12:08:41 -05:00
Jonathan Ballet
e7fe7a32cc
Add missing documentation for ILM metrics (#892)
* Add missing documentation for ILM metrics

Signed-off-by: Jonathan Ballet <jon@multani.info>

* Document the --es.ilm flag

Signed-off-by: Jonathan Ballet <jon@multani.info>

* Apply suggestions from code review

Signed-off-by: Jonathan Ballet <jon@multani.info>

---------

Signed-off-by: Jonathan Ballet <jon@multani.info>
2025-02-15 11:38:20 -05:00
dependabot[bot]
b550e54b4e
Bump github.com/aws/aws-sdk-go-v2/config from 1.28.6 to 1.28.7 (#978)
Bumps [github.com/aws/aws-sdk-go-v2/config](https://github.com/aws/aws-sdk-go-v2) from 1.28.6 to 1.28.7.
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/config/v1.28.6...config/v1.28.7)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2/config
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-01 16:03:59 -05:00
dependabot[bot]
c89f8131bd
Bump github.com/aws/aws-sdk-go-v2/credentials from 1.17.47 to 1.17.48 (#979)
Bumps [github.com/aws/aws-sdk-go-v2/credentials](https://github.com/aws/aws-sdk-go-v2) from 1.17.47 to 1.17.48.
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/credentials/v1.17.47...credentials/v1.17.48)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2/credentials
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-01 15:40:35 -05:00
dependabot[bot]
0355d873cf
Bump github.com/aws/aws-sdk-go-v2/service/sts from 1.33.2 to 1.33.3 (#976)
Bumps [github.com/aws/aws-sdk-go-v2/service/sts](https://github.com/aws/aws-sdk-go-v2) from 1.33.2 to 1.33.3.
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/service/ivs/v1.33.2...service/ivs/v1.33.3)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2/service/sts
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-01 15:28:29 -05:00
PrometheusBot
dbcf459aeb
Update common Prometheus files (#980)
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2025-01-01 15:18:25 -05:00
Ben Kochie
41797efe66
Merge pull request #973 from sysadmind/yamllint
Fix yamllint errors for new Github Actions CI
2025-01-01 13:14:43 +01:00
Joe Adams
7408f21caf
Fix yamllint errors for new Github Actions CI
Signed-off-by: Joe Adams <github@joeadams.io>
2024-12-14 12:03:49 -05:00
Joe Adams
3774123827
Refactor mixin dashboards (#885)
This is a complete refactor of the dashboard system. It brings the dashboard creation, metrics, alerting, etc into alignment with other projects that use jsonnet/grafonnet/mixins. This should allow users to customize what we have created and deploy into their environments. The dashboard was the focus of this iteration, reaching parity with the previous dashboard.

- Add in jsonnet and grafonnet
- Add scripts to compile and lint mixin
- Add CI for the mixin

---------

Signed-off-by: Joe Adams <github@joeadams.io>
2024-12-14 11:52:05 -05:00
Joe Adams
bb6320875c
Add github actions workflow for testing PRs (#959)
* Add github actions workflow for testing PRs

This may need some more work because it's not always easy to test actions locally.

Signed-off-by: Joe Adams <github@joeadams.io>

* Add build and publish jobs

Signed-off-by: Joe Adams <github@joeadams.io>

* Update main branch references with checks for master

Signed-off-by: Joe Adams <github@joeadams.io>

---------

Signed-off-by: Joe Adams <github@joeadams.io>
2024-12-14 11:51:00 -05:00
PrometheusBot
34c4936c53
Update common Prometheus files (#960)
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2024-12-14 11:46:03 -05:00
dependabot[bot]
b846254d5c
Bump github.com/aws/aws-sdk-go-v2/config from 1.28.3 to 1.28.6 (#972)
Bumps [github.com/aws/aws-sdk-go-v2/config](https://github.com/aws/aws-sdk-go-v2) from 1.28.3 to 1.28.6.
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/config/v1.28.3...config/v1.28.6)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2/config
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-14 11:31:15 -05:00
dependabot[bot]
0a6cf82d14
Bump golang.org/x/crypto from 0.28.0 to 0.31.0 (#969)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.28.0 to 0.31.0.
- [Commits](https://github.com/golang/crypto/compare/v0.28.0...v0.31.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-14 11:19:57 -05:00
dependabot[bot]
811cee2182
Bump github.com/aws/aws-sdk-go-v2/credentials from 1.17.44 to 1.17.46 (#965)
Bumps [github.com/aws/aws-sdk-go-v2/credentials](https://github.com/aws/aws-sdk-go-v2) from 1.17.44 to 1.17.46.
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/credentials/v1.17.44...credentials/v1.17.46)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2/credentials
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-14 11:17:08 -05:00
dependabot[bot]
51b1b9a882
Bump github.com/prometheus/exporter-toolkit from 0.13.0 to 0.13.1 (#966)
Bumps [github.com/prometheus/exporter-toolkit](https://github.com/prometheus/exporter-toolkit) from 0.13.0 to 0.13.1.
- [Release notes](https://github.com/prometheus/exporter-toolkit/releases)
- [Changelog](https://github.com/prometheus/exporter-toolkit/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prometheus/exporter-toolkit/compare/v0.13.0...v0.13.1)

---
updated-dependencies:
- dependency-name: github.com/prometheus/exporter-toolkit
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-14 11:10:52 -05:00
dependabot[bot]
c6f86ac844
Bump github.com/aws/aws-sdk-go-v2/config from 1.28.0 to 1.28.3 (#956)
Bumps [github.com/aws/aws-sdk-go-v2/config](https://github.com/aws/aws-sdk-go-v2) from 1.28.0 to 1.28.3.
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/v1.28.0...config/v1.28.3)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2/config
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-10 15:32:37 -05:00
dependabot[bot]
c56248ac02
Bump github.com/aws/aws-sdk-go-v2/service/sts from 1.32.2 to 1.32.3 (#953)
Bumps [github.com/aws/aws-sdk-go-v2/service/sts](https://github.com/aws/aws-sdk-go-v2) from 1.32.2 to 1.32.3.
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/v1.32.2...v1.32.3)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2/service/sts
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-10 15:19:44 -05:00
dependabot[bot]
7ec6712655
Bump github.com/prometheus/common from 0.60.0 to 0.60.1 (#954)
Bumps [github.com/prometheus/common](https://github.com/prometheus/common) from 0.60.0 to 0.60.1.
- [Release notes](https://github.com/prometheus/common/releases)
- [Changelog](https://github.com/prometheus/common/blob/main/RELEASE.md)
- [Commits](https://github.com/prometheus/common/compare/v0.60.0...v0.60.1)

---
updated-dependencies:
- dependency-name: github.com/prometheus/common
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-10 15:12:54 -05:00
PrometheusBot
7f3eeafd7e
Update common Prometheus files (#955)
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2024-11-10 15:12:29 -05:00
Ben Kochie
66b82c8997
Merge pull request #946 from prometheus-community/dependabot/go_modules/github.com/aws/aws-sdk-go-v2/config-1.28.0
Bump github.com/aws/aws-sdk-go-v2/config from 1.27.24 to 1.28.0
2024-10-17 21:50:24 +02:00
dependabot[bot]
3a591ed02e
Bump github.com/aws/aws-sdk-go-v2/config from 1.27.24 to 1.28.0
Bumps [github.com/aws/aws-sdk-go-v2/config](https://github.com/aws/aws-sdk-go-v2) from 1.27.24 to 1.28.0.
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/config/v1.27.24...v1.28.0)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2/config
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-17 19:05:58 +00:00
Ben Kochie
8b44de5a95
Merge pull request #944 from prometheus-community/dependabot/go_modules/github.com/prometheus/client_golang-1.20.5
Bump github.com/prometheus/client_golang from 1.20.4 to 1.20.5
2024-10-17 20:23:55 +02:00
Joe Adams
ca263b9d2e
Update changelog and readme for logging changes (#945)
- Update README to include section about configuring the logging settings.
- Update CHANGELOG with information about breaking changes in the logging output from #942.

Signed-off-by: Joe Adams <github@joeadams.io>
2024-10-17 12:33:23 -04:00
dependabot[bot]
7aa2664f17
Bump github.com/prometheus/client_golang from 1.20.4 to 1.20.5
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.20.4 to 1.20.5.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.20.4...v1.20.5)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-17 16:04:39 +00:00
TJ Hoplock
7a09a847ab
chore!: adopt log/slog, drop go-kit/log (#942)
The bulk of this change set was automated by the following script which
is being used to aid in converting the various exporters/projects to use
slog:

https://gist.github.com/tjhop/49f96fb7ebbe55b12deee0b0312d8434

In addition to the parts that were straightforward conversions, this
also:
- refactors much of the logging config to adopt slog
    - removed custom `logger.go` setup for go-kit
    - adopt promslog/flag and use that to handle parsing log
      level/format flags
    - for consistent behavior, keep log output flag to allow toggle
      stdout/stderr for output
    - adopt promslog for logger setup
- enables sloglint in golangci-lint config
- drops go-kit/log exclusions from lint config
- tidies mods to drop go-kit/log and go-logfmt/logfmt deps

Signed-off-by: TJ Hoplock <t.hoplock@gmail.com>

* ci: update deprecated golangci-lint config

Fixes:

```
WARN [config_reader] The configuration option `linters.errcheck.exclude` is deprecated, please use `linters.errcheck.exclude-functions`.
```

Signed-off-by: TJ Hoplock <t.hoplock@gmail.com>

---------

Signed-off-by: TJ Hoplock <t.hoplock@gmail.com>
2024-10-17 12:03:17 -04:00
Ben Kochie
ccd458b065
Merge pull request #937 from sysadmind/indices-test-refactor
Refactor tests for indices collector
2024-10-16 22:16:03 +02:00
Ben Kochie
33f42c6eab
Merge pull request #936 from sysadmind/nodes-test-refactor
Refactor tests for nodes collector
2024-10-16 22:15:31 +02:00
Ben Kochie
79b0e15fab
Merge pull request #935 from sysadmind/shards-test
Add tests for shards collector
2024-10-16 22:14:55 +02:00
Ben Kochie
77836071b2
Merge pull request #943 from prometheus-community/repo_sync
Synchronize common files from prometheus/prometheus
2024-10-16 22:13:59 +02:00
prombot
3b3879a2ea Update common Prometheus files
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2024-10-16 17:48:55 +00:00
Ben Kochie
b826b14a31
Merge pull request #874 from prometheus-community/repo_sync
Synchronize common files from prometheus/prometheus
2024-10-16 18:36:39 +02:00
Joe Adams
08a1ceea6a
Refactor tests for indices collector
- Refactor tests to test the output of the collector
- Merge tests for index stats and alias
- Add missing metric descriptions in Describe()

Signed-off-by: Joe Adams <github@joeadams.io>
2024-09-28 13:04:59 -04:00
Joe Adams
22d4a8a633
Remove unused var
Signed-off-by: Joe Adams <github@joeadams.io>
2024-09-28 12:27:38 -04:00
Joe Adams
da4a406b39
Remove the useless metrics
Signed-off-by: Joe Adams <github@joeadams.io>
2024-09-28 12:20:34 -04:00
Joe Adams
0fc81859b9
Refactor tests for nodes collector
- Drop extra test for authenticated requests to elasticsearch. Auth is common across all collectors, so it doesn't make sense to have specific tests for an individual collector.
- Add missing descriptions
- Drop tests for minor versions besides the most recent. The output is very large for this collector, and there is little value in testing every single minor version.
- Update tests to test the output of the metrics
- Refactor the node roles metric to have the role be dynamic, and to export 0 values for roles that are missing.

Signed-off-by: Joe Adams <github@joeadams.io>
2024-09-28 12:15:03 -04:00
Tamara Bernshtein
a4f94e585b
added external refresh stats (#933)
Signed-off-by: Tamara Bernshtein <tamara.bernshtein@riskified.com>
Signed-off-by: TomaBere <tamara.bernshtein@riskified.com>
2024-09-28 11:49:21 -04:00
Joe Adams
8103328051
Add tests for shards collector
Signed-off-by: Joe Adams <github@joeadams.io>
2024-09-28 11:29:21 -04:00
Joe Adams
5c8fca8769
Refactor slm collector (#932)
- Move metric Desc to vars to aid in unused linter checks
- Use new Collector interface

Signed-off-by: Joe Adams <github@joeadams.io>
2024-09-20 11:24:21 -04:00
Joe Adams
fd25030ff5
Changes for v1.8.0 (#931)
Update changelog and bump version file

Signed-off-by: Joe Adams <github@joeadams.io>
2024-09-20 10:46:36 -04:00
Joe Adams
d98d2f6185
Refactor tests for slm collector (#928)
- Remove up, totalScrapes, and jsonParseFailures metrics. They are not useful.
- Move fixtures to individual files
- Base tests on the metric output for better testing the expected output instead of the internals.

Signed-off-by: Joe Adams <github@joeadams.io>
2024-09-13 15:11:55 -04:00
Janne Kataja
711a6ce467
CVE-2024-24790: bump go to 1.22.6 (#917)
* bump CircleCI builder image

Signed-off-by: Janne Kataja <janne.kataja@sdx.com>

* bump go to 1.22

Signed-off-by: Janne Kataja <janne.kataja@sdx.com>

---------

Signed-off-by: Janne Kataja <janne.kataja@sdx.com>
2024-09-07 11:52:15 -04:00
Emil Andresen
d13c5552b7
Add metrics to auto scale based on indexing pressure (#904)
* Add metrics indexing_pressure.memory.limit_in_bytes and indexing_pressure.memory.current.current.all_in_bytes to allow auto-scaling based on how close the cluster nodes are to dropping indexing requests due to the indxing request memory buffer reaching capacity.

Signed-off-by: emilandresentac <emil.andresen@telusagcg.com>

* Reduce labels per metric for indexing pressure metrics to cluster, node, and name to save on storage space.

Signed-off-by: emilandresentac <emil.andresen@telusagcg.com>

---------

Signed-off-by: emilandresentac <emil.andresen@telusagcg.com>
2024-07-11 13:45:17 -04:00
Frank Ritchie
bf89cef4de
Update README.md (#911)
The metric

elasticsearch_cluster_health_timed_out

was removed in

320d8b38a5

per

https://github.com/prometheus-community/elasticsearch_exporter/issues/212

Signed-off-by: Frank Ritchie <12985912+fritchie@users.noreply.github.com>
2024-07-11 10:18:06 -04:00
dependabot[bot]
0d92bd3d10
Bump github.com/prometheus/client_golang from 1.18.0 to 1.19.1 (#898)
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.18.0 to 1.19.1.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.18.0...v1.19.1)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-11 09:16:49 -04:00
dependabot[bot]
fed8a6b740
Bump github.com/aws/aws-sdk-go-v2/config from 1.27.4 to 1.27.24 (#910)
Bumps [github.com/aws/aws-sdk-go-v2/config](https://github.com/aws/aws-sdk-go-v2) from 1.27.4 to 1.27.24.
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/config/v1.27.4...config/v1.27.24)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2/config
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-06 12:47:57 -04:00
dependabot[bot]
42c30156ea
Bump github.com/aws/aws-sdk-go-v2 from 1.25.3 to 1.30.1 (#908)
Bumps [github.com/aws/aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2) from 1.25.3 to 1.30.1.
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/v1.25.3...v1.30.1)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-06 12:37:18 -04:00
cello86
2f3360592d
fix: changed permissions information for es.slm (#893)
Signed-off-by: Marcello Lorenzi <m.lorenzi@fineco.it>
Co-authored-by: Marcello Lorenzi <m.lorenzi@fineco.it>
2024-05-16 09:24:35 -04:00
cello86
8ebe0a5056
fix; changed readme.md info snapshots collector (#891)
Signed-off-by: Marcello Lorenzi <m.lorenzi@fineco.it>
Co-authored-by: Marcello Lorenzi <m.lorenzi@fineco.it>
2024-05-14 20:48:51 -04:00
dependabot[bot]
ea789710ce
Bump golang.org/x/net from 0.20.0 to 0.23.0 (#884)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.20.0 to 0.23.0.
- [Commits](https://github.com/golang/net/compare/v0.20.0...v0.23.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-21 15:39:23 -04:00
prombot
08915a5742 Update common Prometheus files
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2024-03-19 17:48:29 +00:00
PrometheusBot
51401e4b82
Update common Prometheus files (#873)
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2024-03-19 09:58:26 -04:00
PrometheusBot
00814928b4
Update common Prometheus files (#861)
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2024-03-13 23:01:54 -04:00
dependabot[bot]
08d9748697
Bump github.com/aws/aws-sdk-go-v2/credentials from 1.17.4 to 1.17.7 (#871)
Bumps [github.com/aws/aws-sdk-go-v2/credentials](https://github.com/aws/aws-sdk-go-v2) from 1.17.4 to 1.17.7.
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/v1.17.7/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/v1.17.4...v1.17.7)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2/credentials
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-13 22:42:13 -04:00
dependabot[bot]
e1ddc12424
Bump github.com/aws/aws-sdk-go-v2/service/sts from 1.28.1 to 1.28.4 (#872)
Bumps [github.com/aws/aws-sdk-go-v2/service/sts](https://github.com/aws/aws-sdk-go-v2) from 1.28.1 to 1.28.4.
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/service/ecs/v1.28.1...service/emr/v1.28.4)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2/service/sts
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-13 22:33:03 -04:00
Aaron Delaney
1d5d44be41
collector: add tasks API collection (#778)
* collector: add tasks API collection

This commit adds simple aggregation of Elasticsearch Tasks API.
There are 4 new metrics; though 3 are just bookkeeping.

elasticsearch_task_stats_action_total is a gague reporting the total
number of tasks running for a given action. Because there are no stats
endpoints available for this, this change introduces an aggregation step
to group the number of tasks by action name.

This metric is useful for ensuring long running actions of a specific
kind stay within a specific limit. Of particular use to me is
the action: 'indices:data/write/delete/byquery'.

In my usecase, our ES access patterns mean we have a predefined limit
of these actions running on the cluster.

This change also adds two new CLI flags to manage the collection of tasks API:

	--es.tasks (to enable task collection)
	--es.tasks.actions (to filter tasks by action param)

Issue #525 proposed addition of collection of these tasks.

Signed-off-by: Aaron Delaney <apd@arista.com>

* collector: use collector interface for tasks

Signed-off-by: Aaron Delaney <apd@arista.com>

* all: fix issues reported by golangci-lint

Signed-off-by: Aaron Delaney <apd@arista.com>

* collector: make task structs private to package

Signed-off-by: Aaron Delaney <apd@arista.com>

* Fix task stats metric name

Signed-off-by: Aaron Delaney <apd@arista.com>

* Fix tasks test

Signed-off-by: Aaron Delaney <apd@arista.com>

---------

Signed-off-by: Aaron Delaney <apd@arista.com>
2024-03-13 22:26:39 -04:00
dependabot[bot]
1810f7c30b
Bump github.com/aws/aws-sdk-go-v2/config from 1.26.6 to 1.27.4 (#868)
Bumps [github.com/aws/aws-sdk-go-v2/config](https://github.com/aws/aws-sdk-go-v2) from 1.26.6 to 1.27.4.
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/config/v1.26.6...config/v1.27.4)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2/config
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-13 22:23:51 -04:00
dependabot[bot]
c2c33b1681
Bump google.golang.org/protobuf from 1.32.0 to 1.33.0 (#869)
Bumps google.golang.org/protobuf from 1.32.0 to 1.33.0.

---
updated-dependencies:
- dependency-name: google.golang.org/protobuf
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-13 22:20:00 -04:00
PrometheusBot
c276c3e0ea
Update common Prometheus files (#858)
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2024-02-21 21:47:04 -05:00
Ben Kochie
e730d38034
Merge pull request #852 from prometheus-community/dependabot/go_modules/github.com/aws/aws-sdk-go-v2/config-1.26.6
Bump github.com/aws/aws-sdk-go-v2/config from 1.25.11 to 1.26.6
2024-02-04 16:13:07 +01:00
dependabot[bot]
6010fd106a
Bump github.com/aws/aws-sdk-go-v2/config from 1.25.11 to 1.26.6
Bumps [github.com/aws/aws-sdk-go-v2/config](https://github.com/aws/aws-sdk-go-v2) from 1.25.11 to 1.26.6.
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/config/v1.25.11...config/v1.26.6)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2/config
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-04 11:37:39 +00:00
Ben Kochie
066b7eac3d
Merge pull request #855 from prometheus-community/dependabot/go_modules/github.com/aws/aws-sdk-go-v2/service/sts-1.26.7
Bump github.com/aws/aws-sdk-go-v2/service/sts from 1.26.2 to 1.26.7
2024-02-04 12:36:44 +01:00
Ben Kochie
3588461cf6
Merge pull request #856 from prometheus-community/dependabot/go_modules/github.com/prometheus/common-0.46.0
Bump github.com/prometheus/common from 0.45.0 to 0.46.0
2024-02-04 12:36:07 +01:00
dependabot[bot]
7b0ebe5370
Bump github.com/prometheus/common from 0.45.0 to 0.46.0
Bumps [github.com/prometheus/common](https://github.com/prometheus/common) from 0.45.0 to 0.46.0.
- [Release notes](https://github.com/prometheus/common/releases)
- [Commits](https://github.com/prometheus/common/compare/v0.45.0...v0.46.0)

---
updated-dependencies:
- dependency-name: github.com/prometheus/common
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-01 14:40:45 +00:00
dependabot[bot]
56dc80b394
Bump github.com/aws/aws-sdk-go-v2/service/sts from 1.26.2 to 1.26.7
Bumps [github.com/aws/aws-sdk-go-v2/service/sts](https://github.com/aws/aws-sdk-go-v2) from 1.26.2 to 1.26.7.
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/config/v1.26.2...service/s3/v1.26.7)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2/service/sts
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-01 14:40:39 +00:00
PrometheusBot
fcf5f83d90
Update common Prometheus files (#848)
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2024-01-09 10:56:11 -05:00
dependabot[bot]
b729189b61
Bump github.com/prometheus/client_golang from 1.17.0 to 1.18.0 (#843)
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.17.0 to 1.18.0.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.17.0...v1.18.0)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-03 14:26:42 -05:00
dependabot[bot]
083bfe2418
Bump github.com/prometheus/exporter-toolkit from 0.10.0 to 0.11.0 (#845)
Bumps [github.com/prometheus/exporter-toolkit](https://github.com/prometheus/exporter-toolkit) from 0.10.0 to 0.11.0.
- [Release notes](https://github.com/prometheus/exporter-toolkit/releases)
- [Changelog](https://github.com/prometheus/exporter-toolkit/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prometheus/exporter-toolkit/compare/v0.10.0...v0.11.0)

---
updated-dependencies:
- dependency-name: github.com/prometheus/exporter-toolkit
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-02 18:16:15 -05:00
PrometheusBot
b24d0ace72
Update common Prometheus files (#839)
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2023-12-22 15:27:33 -05:00
PrometheusBot
a20eec030c
Update common Prometheus files (#835)
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2023-12-21 14:59:12 -05:00
Ali
1a82b986e6
Update README.md (#830)
* Update README.md

The following flag has been replaced but it is not mentioned in the main readme file and only in release notes which makes this prone for confusion.
--es.cluster_settings has been renamed to --collector.clustersettings



Signed-off-by: Ali <115415312+xogoodnow@users.noreply.github.com>

* Update README.md

Updated "Elasticsearch 7.x security privileges" section on "collector.clustersettings" flag

Signed-off-by: Ali <115415312+xogoodnow@users.noreply.github.com>

* Update README.md

Omitted "es.cluster_settings" flag.
Also added description so users who are using the older version would not be confused at first glance.

Signed-off-by: Ali <115415312+xogoodnow@users.noreply.github.com>

* Update README.md

The "es.cluster_settings" flag must also be omitted from this section "Elasticsearch 7.x security privileges".

Signed-off-by: Ali <115415312+xogoodnow@users.noreply.github.com>

* Update README.md

Since the order is alphabetical this flag should come first.
My bad :)

Signed-off-by: Ali <115415312+xogoodnow@users.noreply.github.com>

---------

Signed-off-by: Ali <115415312+xogoodnow@users.noreply.github.com>
2023-12-21 14:54:05 -05:00
121 changed files with 18210 additions and 5670 deletions

View File

@ -1,52 +0,0 @@
---
version: 2.1
orbs:
prometheus: prometheus/prometheus@0.17.1
executors:
# This must match .promu.yml.
golang:
docker:
- image: cimg/go:1.21
jobs:
test:
executor: golang
steps:
- prometheus/setup_environment
- run: make
- prometheus/store_artifact:
file: elasticsearch_exporter
workflows:
version: 2
elasticsearch_exporter:
jobs:
- test:
filters:
tags:
only: /.*/
- prometheus/build:
name: build
filters:
tags:
only: /.*/
- prometheus/publish_master:
context: org-context
docker_hub_organization: prometheuscommunity
quay_io_organization: prometheuscommunity
requires:
- test
- build
filters:
branches:
only: master
- prometheus/publish_release:
context: org-context
docker_hub_organization: prometheuscommunity
quay_io_organization: prometheuscommunity
requires:
- test
- build
filters:
tags:
only: /^v.*/
branches:
ignore: /.*/

View File

@ -4,3 +4,11 @@ updates:
directory: "/"
schedule:
interval: "monthly"
groups:
aws:
patterns:
- "github.com/aws/*"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly"

107
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,107 @@
---
name: CI
on:
pull_request:
push:
jobs:
test_go:
name: Go tests
runs-on: ubuntu-latest
container:
# Whenever the Go version is updated here, .promu.yml
# should also be updated.
image: quay.io/prometheus/golang-builder:1.25-base
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: prometheus/promci@c0916f0a41f13444612a8f0f5e700ea34edd7c19 # v0.5.3
- uses: ./.github/promci/actions/setup_environment
- run: make GO_ONLY=1 SKIP_GOLANGCI_LINT=1
build:
name: Build Prometheus for common architectures
runs-on: ubuntu-latest
if: |
!(github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v'))
&&
!(github.event_name == 'pull_request' && startsWith(github.event.pull_request.base.ref, 'release-'))
&&
!(github.event_name == 'push' && github.event.ref == 'refs/heads/main')
&&
!(github.event_name == 'push' && github.event.ref == 'refs/heads/master')
strategy:
matrix:
thread: [ 0, 1, 2 ]
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: prometheus/promci@c0916f0a41f13444612a8f0f5e700ea34edd7c19 # v0.5.3
- uses: ./.github/promci/actions/build
with:
promu_opts: "-p linux/amd64 -p windows/amd64 -p linux/arm64 -p darwin/amd64 -p darwin/arm64 -p linux/386"
parallelism: 3
thread: ${{ matrix.thread }}
build_all:
name: Build Prometheus for all architectures
runs-on: ubuntu-latest
if: |
(github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v'))
||
(github.event_name == 'pull_request' && startsWith(github.event.pull_request.base.ref, 'release-'))
||
(github.event_name == 'push' && github.event.ref == 'refs/heads/main')
||
(github.event_name == 'push' && github.event.ref == 'refs/heads/master')
strategy:
matrix:
thread: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ]
# Whenever the Go version is updated here, .promu.yml
# should also be updated.
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: prometheus/promci@c0916f0a41f13444612a8f0f5e700ea34edd7c19 # v0.5.3
- uses: ./.github/promci/actions/build
with:
parallelism: 12
thread: ${{ matrix.thread }}
publish_main:
# https://github.com/prometheus/promci/blob/52c7012f5f0070d7281b8db4a119e21341d43c91/actions/publish_main/action.yml
name: Publish main branch artifacts
runs-on: ubuntu-latest
needs: [test_go, build_all]
if: |
(github.event_name == 'push' && github.event.ref == 'refs/heads/main')
||
(github.event_name == 'push' && github.event.ref == 'refs/heads/master')
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: prometheus/promci@c0916f0a41f13444612a8f0f5e700ea34edd7c19 # v0.5.3
- uses: ./.github/promci/actions/publish_main
with:
docker_hub_organization: prometheuscommunity
docker_hub_login: ${{ secrets.docker_hub_login }}
docker_hub_password: ${{ secrets.docker_hub_password }}
quay_io_organization: prometheuscommunity
quay_io_login: ${{ secrets.quay_io_login }}
quay_io_password: ${{ secrets.quay_io_password }}
publish_release:
name: Publish release artefacts
runs-on: ubuntu-latest
needs: [test_go, build_all]
if: |
(github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v'))
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: prometheus/promci@c0916f0a41f13444612a8f0f5e700ea34edd7c19 # v0.5.3
- uses: ./.github/promci/actions/publish_release
with:
docker_hub_organization: prometheuscommunity
docker_hub_login: ${{ secrets.docker_hub_login }}
docker_hub_password: ${{ secrets.docker_hub_password }}
quay_io_organization: prometheuscommunity
quay_io_login: ${{ secrets.quay_io_login }}
quay_io_password: ${{ secrets.quay_io_password }}
github_token: ${{ secrets.PROMBOT_GITHUB_TOKEN }}

View File

@ -0,0 +1,61 @@
---
name: Push README to Docker Hub
on:
push:
paths:
- "README.md"
- "README-containers.md"
- ".github/workflows/container_description.yml"
branches: [ main, master ]
permissions:
contents: read
jobs:
PushDockerHubReadme:
runs-on: ubuntu-latest
name: Push README to Docker Hub
if: github.repository_owner == 'prometheus' || github.repository_owner == 'prometheus-community' # Don't run this workflow on forks.
steps:
- name: git checkout
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: Set docker hub repo name
run: echo "DOCKER_REPO_NAME=$(make docker-repo-name)" >> $GITHUB_ENV
- name: Push README to Dockerhub
uses: christian-korneck/update-container-description-action@d36005551adeaba9698d8d67a296bd16fa91f8e8 # v1
env:
DOCKER_USER: ${{ secrets.DOCKER_HUB_LOGIN }}
DOCKER_PASS: ${{ secrets.DOCKER_HUB_PASSWORD }}
with:
destination_container_repo: ${{ env.DOCKER_REPO_NAME }}
provider: dockerhub
short_description: ${{ env.DOCKER_REPO_NAME }}
# Empty string results in README-containers.md being pushed if it
# exists. Otherwise, README.md is pushed.
readme_file: ''
PushQuayIoReadme:
runs-on: ubuntu-latest
name: Push README to quay.io
if: github.repository_owner == 'prometheus' || github.repository_owner == 'prometheus-community' # Don't run this workflow on forks.
steps:
- name: git checkout
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: Set quay.io org name
run: echo "DOCKER_REPO=$(echo quay.io/${GITHUB_REPOSITORY_OWNER} | tr -d '-')" >> $GITHUB_ENV
- name: Set quay.io repo name
run: echo "DOCKER_REPO_NAME=$(make docker-repo-name)" >> $GITHUB_ENV
- name: Push README to quay.io
uses: christian-korneck/update-container-description-action@d36005551adeaba9698d8d67a296bd16fa91f8e8 # v1
env:
DOCKER_APIKEY: ${{ secrets.QUAY_IO_API_TOKEN }}
with:
destination_container_repo: ${{ env.DOCKER_REPO_NAME }}
provider: quay
# Empty string results in README-containers.md being pushed if it
# exists. Otherwise, README.md is pushed.
readme_file: ''

View File

@ -12,21 +12,33 @@ on:
- ".golangci.yml"
pull_request:
permissions: # added using https://github.com/step-security/secure-repo
contents: read
jobs:
golangci:
permissions:
contents: read # for actions/checkout to fetch code
pull-requests: read # for golangci/golangci-lint-action to fetch pull requests
name: lint
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: install Go
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
go-version: 1.21.x
persist-credentials: false
- name: Install Go
uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0
with:
go-version: 1.25.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: Get golangci-lint version
id: golangci-lint-version
run: echo "version=$(make print-golangci-lint-version)" >> $GITHUB_OUTPUT
- name: Lint
uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc # v3.7.0
uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0
with:
version: v1.54.2
args: --verbose
version: ${{ steps.golangci-lint-version.outputs.version }}

34
.github/workflows/mixin.yml vendored Normal file
View File

@ -0,0 +1,34 @@
---
name: mixin
on:
pull_request:
paths:
- "elasticsearch-mixin/**"
jobs:
check-mixin:
name: check
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Setup Go
uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0
with:
go-version: 1.25.x
- name: Install dependencies
run: |
go install github.com/google/go-jsonnet/cmd/jsonnet@v0.20.0
go install github.com/google/go-jsonnet/cmd/jsonnetfmt@v0.20.0
go install github.com/google/go-jsonnet/cmd/jsonnet-lint@v0.20.0
go install github.com/monitoring-mixins/mixtool/cmd/mixtool@16dc166166d91e93475b86b9355a4faed2400c18
go install github.com/jsonnet-bundler/jsonnet-bundler/cmd/jb@v0.5.1
- name: Lint
run: bash ./scripts/lint-jsonnet.sh
- name: Compile mixin
run: bash ./scripts/compile-mixin.sh
- name: Verify compiled mixin matches repo
run: |
git diff --exit-code -- ./elasticsearch-mixin || (echo "Compiled mixin does not match repo" && exit 1)
# Check if there are any new untracked files
test -z "$(git status --porcelain)" || (echo "Untracked files found, please run ./scripts/compile-mixin.sh" && exit 1)

1
.gitignore vendored
View File

@ -4,3 +4,4 @@ elasticsearch_exporter
*-stamp
.tarballs
/vendor
vendor/

View File

@ -1,20 +1,124 @@
---
version: "2"
formatters:
enable:
- gci
- gofumpt
settings:
gci:
sections:
- standard
- prefix(github.com/prometheus-community/elasticsearch_exporter)
- default
linters:
enable:
- depguard
# TODO(@sysadmind): Enable and fix the issues.
# - errorlint
- exptostd
# TODO(@sysadmind): Enable and fix the issues.
# - gocritic
# - godot
- loggercheck
# TODO(@sysadmind): Enable and fix the issues.
# - misspell
- nilnesserr
- nolintlint
# TODO(@sysadmind): Enable and fix the issues.
# - perfsprint
- predeclared
- revive
issues:
exclude-rules:
- path: _test.go
linters:
- errcheck
linters-settings:
errcheck:
exclude: scripts/errcheck_excludes.txt
revive:
- sloglint
- testifylint
- unconvert
- unused
- usestdlibvars
- whitespace
exclusions:
rules:
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unused-parameter
- name: unused-parameter
severity: warning
disabled: true
# Disable errcheck for test files.
- linters:
- errcheck
path: _test.go
# Disable errcheck rule for some specific functions.
- linters:
- errcheck
# Taken from the default exclusions in v1.
text: Error return value of .((os\.)?std(out|err)\..*|.*Close|.*Flush|os\.Remove(All)?|.*print(f|ln)?|os\.(Un)?Setenv). is not checked
settings:
revive:
rules:
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md
- name: blank-imports
- name: comment-spacings
- name: context-as-argument
arguments:
# Allow functions with test or bench signatures.
- allowTypesBefore: '*testing.T,testing.TB'
- name: context-keys-type
- name: dot-imports
- name: early-return
arguments:
- "preserveScope"
# A lot of false positives: incorrectly identifies channel draining as "empty code block".
# See https://github.com/mgechev/revive/issues/386
- name: empty-block
disabled: true
- name: error-naming
- name: error-return
- name: error-strings
- name: errorf
# TODO(@sysadmind): Enable and fix the issues.
# - name: exported
- name: increment-decrement
- name: indent-error-flow
arguments:
- "preserveScope"
- name: package-comments
# TODO(beorn7/sysadmind): Currently, we have a lot of missing package doc comments. Maybe we should have them.
disabled: true
- name: range
- name: receiver-naming
- name: redefines-builtin-id
- name: superfluous-else
arguments:
- "preserveScope"
- name: time-naming
# TODO(@sysadmind): Enable and fix the issues.
# - name: unexported-return
- name: unreachable-code
- name: unused-parameter
severity: warning
disabled: true
- name: var-declaration
- name: var-naming
depguard:
rules:
main:
deny:
- pkg: "sync/atomic"
desc: "Use go.uber.org/atomic instead of sync/atomic"
- pkg: "github.com/stretchr/testify/assert"
desc: "Use github.com/stretchr/testify/require instead of github.com/stretchr/testify/assert"
- pkg: "github.com/go-kit/kit/log"
desc: "Use github.com/go-kit/log instead of github.com/go-kit/kit/log"
- pkg: "io/ioutil"
desc: "Use corresponding 'os' or 'io' functions instead."
- pkg: "regexp"
desc: "Use github.com/grafana/regexp instead of regexp"
- pkg: "github.com/pkg/errors"
desc: "Use 'errors' or 'fmt' instead of github.com/pkg/errors"
- pkg: "gzip"
desc: "Use github.com/klauspost/compress instead of gzip"
- pkg: "zlib"
desc: "Use github.com/klauspost/compress instead of zlib"
- pkg: "golang.org/x/exp/slices"
desc: "Use 'slices' instead."
issues:
max-issues-per-linter: 0
max-same-issues: 0

View File

@ -1,6 +1,7 @@
go:
# This must match .circle/config.yml.
version: 1.21
# Whenever the Go version is updated here,
# .github/workflows should also be updated.
version: 1.25
repository:
path: github.com/prometheus-community/elasticsearch_exporter
build:

View File

@ -1,5 +1,8 @@
---
extends: default
ignore: |
**/node_modules
web/api/v1/testdata/openapi_*_golden.yaml
rules:
braces:

View File

@ -1,3 +1,43 @@
## master / unreleased
## 1.10.0 / 2025-12-02
### BREAKING CHANGES
* `--es.uri` now defaults to empty string #1063
* The flag `--es.data_stream` has been renamed to `--collector.data-stream`.
* The flag `--es.ilm` has been renamed to `--collector.ilm`.
### Changelog
* [SECURITY] Remove logging unsanitized URL when HTTP request fails #1051
* [CHANGE] Rename --es.data_stream to --collector.data-stream #983
* [CHANGE] Rename --es.ilm to --collector.ilm #999
* [FEATURE] Add multi-target scraping via /probe endpoint #1063
* [FEATURE] Add health-report collector #1002
* [FEATURE] Add pprof profiling #1033
* [ENHANCEMENT] Ensure time.Ticker is released #1049
* [BUGFIX] Fix disk watermark values json parsing #1055
* [BUGFIX] Change collector failure log level to warning #1050
## 1.9.0 / 2025-02-27
BREAKING CHANGES:
The flag `--es.slm` has been renamed to `--collector.slm`.
The logging system has been replaced with log/slog from the stdlib. This change is being made across the prometheus ecosystem. The logging output has changed, but the messages and levels remain the same. The `ts` label for the timestamp has bewen replaced with `time`, the accuracy is less, and the timezone is not forced to UTC. The `caller` field has been replaced by the `source` field, which now includes the full path to the source file. The `level` field now exposes the log level in capital letters.
* [CHANGE] Rename --es.slm to --collector.slm #932
* [CHANGE] Replace logging system #942
* [ENHANCEMENT] Add external refresh stats #933
## 1.8.0 / 2024-09-14
* [FEATURE] Add tasks action collector. Enable using `--collector.tasks.actions`. #778
* [FEATURE] Add additional nodes metrics for indexing pressure monitoring. #904
## 1.7.0 / 2023-12-02
BREAKING CHANGES:

View File

@ -1,4 +1,4 @@
# Copyright 2018 The Prometheus Authors
# Copyright 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
@ -49,23 +49,24 @@ endif
GOTEST := $(GO) test
GOTEST_DIR :=
ifneq ($(CIRCLE_JOB),)
ifneq ($(shell command -v gotestsum > /dev/null),)
ifneq ($(shell command -v gotestsum 2> /dev/null),)
GOTEST_DIR := test-results
GOTEST := gotestsum --junitfile $(GOTEST_DIR)/unit-tests.xml --
endif
endif
PROMU_VERSION ?= 0.15.0
PROMU_VERSION ?= 0.17.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.55.2
# golangci-lint only supports linux, darwin and windows platforms on i386/amd64.
GOLANGCI_LINT_VERSION ?= v2.7.2
GOLANGCI_FMT_OPTS ?=
# golangci-lint only supports linux, darwin and windows platforms on i386/amd64/arm64.
# windows isn't included here because of the path separator being different.
ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin))
ifeq ($(GOHOSTARCH),$(filter $(GOHOSTARCH),amd64 i386))
ifeq ($(GOHOSTARCH),$(filter $(GOHOSTARCH),amd64 i386 arm64))
# 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.
ifneq (,$(SKIP_GOLANGCI_LINT))
@ -81,11 +82,32 @@ endif
PREFIX ?= $(shell pwd)
BIN_DIR ?= $(shell pwd)
DOCKER_IMAGE_TAG ?= $(subst /,-,$(shell git rev-parse --abbrev-ref HEAD))
DOCKERFILE_PATH ?= ./Dockerfile
DOCKERBUILD_CONTEXT ?= ./
DOCKER_REPO ?= prom
# Check if deprecated DOCKERFILE_PATH is set
ifdef DOCKERFILE_PATH
$(error DOCKERFILE_PATH is deprecated. Use DOCKERFILE_VARIANTS ?= $(DOCKERFILE_PATH) in the Makefile)
endif
DOCKER_ARCHS ?= amd64
DOCKERFILE_VARIANTS ?= Dockerfile $(wildcard Dockerfile.*)
# Function to extract variant from Dockerfile label.
# Returns the variant name from io.prometheus.image.variant label, or "default" if not found.
define dockerfile_variant
$(strip $(or $(shell sed -n 's/.*io\.prometheus\.image\.variant="\([^"]*\)".*/\1/p' $(1)),default))
endef
# Check for duplicate variant names (including default for Dockerfiles without labels).
DOCKERFILE_VARIANT_NAMES := $(foreach df,$(DOCKERFILE_VARIANTS),$(call dockerfile_variant,$(df)))
DOCKERFILE_VARIANT_NAMES_SORTED := $(sort $(DOCKERFILE_VARIANT_NAMES))
ifneq ($(words $(DOCKERFILE_VARIANT_NAMES)),$(words $(DOCKERFILE_VARIANT_NAMES_SORTED)))
$(error Duplicate variant names found. Each Dockerfile must have a unique io.prometheus.image.variant label, and only one can be without a label (default))
endif
# Build variant:dockerfile pairs for shell iteration.
DOCKERFILE_VARIANTS_WITH_NAMES := $(foreach df,$(DOCKERFILE_VARIANTS),$(call dockerfile_variant,$(df)):$(df))
BUILD_DOCKER_ARCHS = $(addprefix common-docker-,$(DOCKER_ARCHS))
PUBLISH_DOCKER_ARCHS = $(addprefix common-docker-publish-,$(DOCKER_ARCHS))
@ -111,7 +133,7 @@ common-all: precheck style check_license lint yamllint unused build test
.PHONY: common-style
common-style:
@echo ">> checking code style"
@fmtRes=$$($(GOFMT) -d $$(find . -path ./vendor -prune -o -name '*.go' -print)); \
@fmtRes=$$($(GOFMT) -d $$(git ls-files '*.go' ':!:vendor/*' || find . -path ./vendor -prune -o -name '*.go' -print)); \
if [ -n "$${fmtRes}" ]; then \
echo "gofmt checking failed!"; echo "$${fmtRes}"; echo; \
echo "Please ensure you are using $$($(GO) version) for formatting code."; \
@ -121,13 +143,19 @@ common-style:
.PHONY: common-check_license
common-check_license:
@echo ">> checking license header"
@licRes=$$(for file in $$(find . -type f -iname '*.go' ! -path './vendor/*') ; do \
@licRes=$$(for file in $$(git ls-files '*.go' ':!:vendor/*' || find . -path ./vendor -prune -o -type f -iname '*.go' -print) ; do \
awk 'NR<=3' $$file | grep -Eq "(Copyright|generated|GENERATED)" || echo $$file; \
done); \
if [ -n "$${licRes}" ]; then \
echo "license header checking failed:"; echo "$${licRes}"; \
exit 1; \
fi
@echo ">> checking for copyright years 2026 or later"
@futureYearRes=$$(git grep -E 'Copyright (202[6-9]|20[3-9][0-9])' -- '*.go' ':!:vendor/*' || true); \
if [ -n "$${futureYearRes}" ]; then \
echo "Files with copyright year 2026 or later found (should use 'Copyright The Prometheus Authors'):"; echo "$${futureYearRes}"; \
exit 1; \
fi
.PHONY: common-deps
common-deps:
@ -138,7 +166,7 @@ common-deps:
update-go-deps:
@echo ">> updating Go dependencies"
@for m in $$($(GO) list -mod=readonly -m -f '{{ if and (not .Indirect) (not .Main)}}{{.Path}}{{end}}' all); do \
$(GO) get -d $$m; \
$(GO) get $$m; \
done
$(GO) mod tidy
@ -156,9 +184,13 @@ $(GOTEST_DIR):
@mkdir -p $@
.PHONY: common-format
common-format:
common-format: $(GOLANGCI_LINT)
@echo ">> formatting code"
$(GO) fmt $(pkgs)
ifdef GOLANGCI_LINT
@echo ">> formatting code with golangci-lint"
$(GOLANGCI_LINT) fmt $(GOLANGCI_FMT_OPTS)
endif
.PHONY: common-vet
common-vet:
@ -169,16 +201,20 @@ common-vet:
common-lint: $(GOLANGCI_LINT)
ifdef GOLANGCI_LINT
@echo ">> running golangci-lint"
# 'go list' needs to be executed before staticcheck to prepopulate the modules cache.
# Otherwise staticcheck might fail randomly for some reason not yet explained.
$(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-lint-fix
common-lint-fix: $(GOLANGCI_LINT)
ifdef GOLANGCI_LINT
@echo ">> running golangci-lint fix"
$(GOLANGCI_LINT) run --fix $(GOLANGCI_LINT_OPTS) $(pkgs)
endif
.PHONY: common-yamllint
common-yamllint:
@echo ">> running yamllint on all YAML files in the repository"
ifeq (, $(shell command -v yamllint > /dev/null))
ifeq (, $(shell command -v yamllint 2> /dev/null))
@echo "yamllint not installed so skipping"
else
yamllint .
@ -204,31 +240,117 @@ common-tarball: promu
@echo ">> building release tarball"
$(PROMU) tarball --prefix $(PREFIX) $(BIN_DIR)
.PHONY: common-docker-repo-name
common-docker-repo-name:
@echo "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)"
.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-$*:$(SANITIZED_DOCKER_IMAGE_TAG)" \
-f $(DOCKERFILE_PATH) \
--build-arg ARCH="$*" \
--build-arg OS="linux" \
$(DOCKERBUILD_CONTEXT)
@for variant in $(DOCKERFILE_VARIANTS_WITH_NAMES); do \
dockerfile=$${variant#*:}; \
variant_name=$${variant%%:*}; \
distroless_arch="$*"; \
if [ "$*" = "armv7" ]; then \
distroless_arch="arm"; \
fi; \
if [ "$$dockerfile" = "Dockerfile" ]; then \
echo "Building default variant ($$variant_name) for linux-$* using $$dockerfile"; \
docker build -t "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)" \
-f $$dockerfile \
--build-arg ARCH="$*" \
--build-arg OS="linux" \
--build-arg DISTROLESS_ARCH="$$distroless_arch" \
$(DOCKERBUILD_CONTEXT); \
if [ "$$variant_name" != "default" ]; then \
echo "Tagging default variant with $$variant_name suffix"; \
docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)" \
"$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)-$$variant_name"; \
fi; \
else \
echo "Building $$variant_name variant for linux-$* using $$dockerfile"; \
docker build -t "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)-$$variant_name" \
-f $$dockerfile \
--build-arg ARCH="$*" \
--build-arg OS="linux" \
--build-arg DISTROLESS_ARCH="$$distroless_arch" \
$(DOCKERBUILD_CONTEXT); \
fi; \
done
.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-$*:$(SANITIZED_DOCKER_IMAGE_TAG)"
@for variant in $(DOCKERFILE_VARIANTS_WITH_NAMES); do \
dockerfile=$${variant#*:}; \
variant_name=$${variant%%:*}; \
if [ "$$dockerfile" != "Dockerfile" ] || [ "$$variant_name" != "default" ]; then \
echo "Pushing $$variant_name variant for linux-$*"; \
docker push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)-$$variant_name"; \
fi; \
if [ "$$dockerfile" = "Dockerfile" ]; then \
echo "Pushing default variant ($$variant_name) for linux-$*"; \
docker push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)"; \
fi; \
if [ "$(DOCKER_IMAGE_TAG)" = "latest" ]; then \
if [ "$$dockerfile" != "Dockerfile" ] || [ "$$variant_name" != "default" ]; then \
echo "Pushing $$variant_name variant version tags for linux-$*"; \
docker push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:v$(DOCKER_MAJOR_VERSION_TAG)-$$variant_name"; \
fi; \
if [ "$$dockerfile" = "Dockerfile" ]; then \
echo "Pushing default variant version tag for linux-$*"; \
docker push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:v$(DOCKER_MAJOR_VERSION_TAG)"; \
fi; \
fi; \
done
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-$*:$(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)"
@for variant in $(DOCKERFILE_VARIANTS_WITH_NAMES); do \
dockerfile=$${variant#*:}; \
variant_name=$${variant%%:*}; \
if [ "$$dockerfile" != "Dockerfile" ] || [ "$$variant_name" != "default" ]; then \
echo "Tagging $$variant_name variant for linux-$* as latest"; \
docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)-$$variant_name" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:latest-$$variant_name"; \
docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)-$$variant_name" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:v$(DOCKER_MAJOR_VERSION_TAG)-$$variant_name"; \
fi; \
if [ "$$dockerfile" = "Dockerfile" ]; then \
echo "Tagging default variant ($$variant_name) for linux-$* as latest"; \
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)"; \
fi; \
done
.PHONY: common-docker-manifest
common-docker-manifest:
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)"
@for variant in $(DOCKERFILE_VARIANTS_WITH_NAMES); do \
dockerfile=$${variant#*:}; \
variant_name=$${variant%%:*}; \
if [ "$$dockerfile" != "Dockerfile" ] || [ "$$variant_name" != "default" ]; then \
echo "Creating manifest for $$variant_name variant"; \
DOCKER_CLI_EXPERIMENTAL=enabled docker manifest create -a "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(SANITIZED_DOCKER_IMAGE_TAG)-$$variant_name" $(foreach ARCH,$(DOCKER_ARCHS),$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$(ARCH):$(SANITIZED_DOCKER_IMAGE_TAG)-$$variant_name); \
DOCKER_CLI_EXPERIMENTAL=enabled docker manifest push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(SANITIZED_DOCKER_IMAGE_TAG)-$$variant_name"; \
fi; \
if [ "$$dockerfile" = "Dockerfile" ]; then \
echo "Creating default variant ($$variant_name) manifest"; \
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)"; \
fi; \
if [ "$(DOCKER_IMAGE_TAG)" = "latest" ]; then \
if [ "$$dockerfile" != "Dockerfile" ] || [ "$$variant_name" != "default" ]; then \
echo "Creating manifest for $$variant_name variant version tag"; \
DOCKER_CLI_EXPERIMENTAL=enabled docker manifest create -a "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):v$(DOCKER_MAJOR_VERSION_TAG)-$$variant_name" $(foreach ARCH,$(DOCKER_ARCHS),$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$(ARCH):v$(DOCKER_MAJOR_VERSION_TAG)-$$variant_name); \
DOCKER_CLI_EXPERIMENTAL=enabled docker manifest push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):v$(DOCKER_MAJOR_VERSION_TAG)-$$variant_name"; \
fi; \
if [ "$$dockerfile" = "Dockerfile" ]; then \
echo "Creating default variant version tag manifest"; \
DOCKER_CLI_EXPERIMENTAL=enabled docker manifest create -a "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):v$(DOCKER_MAJOR_VERSION_TAG)" $(foreach ARCH,$(DOCKER_ARCHS),$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$(ARCH):v$(DOCKER_MAJOR_VERSION_TAG)); \
DOCKER_CLI_EXPERIMENTAL=enabled docker manifest push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):v$(DOCKER_MAJOR_VERSION_TAG)"; \
fi; \
fi; \
done
.PHONY: promu
promu: $(PROMU)
@ -240,8 +362,8 @@ $(PROMU):
cp $(PROMU_TMP)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM)/promu $(FIRST_GOPATH)/bin/promu
rm -r $(PROMU_TMP)
.PHONY: proto
proto:
.PHONY: common-proto
common-proto:
@echo ">> generating code from proto files"
@./scripts/genproto.sh
@ -253,6 +375,10 @@ $(GOLANGCI_LINT):
| sh -s -- -b $(FIRST_GOPATH)/bin $(GOLANGCI_LINT_VERSION)
endif
.PHONY: common-print-golangci-lint-version
common-print-golangci-lint-version:
@echo $(GOLANGCI_LINT_VERSION)
.PHONY: precheck
precheck::
@ -267,3 +393,9 @@ $(1)_precheck:
exit 1; \
fi
endef
govulncheck: install-govulncheck
govulncheck ./...
install-govulncheck:
command -v govulncheck > /dev/null || go install golang.org/x/vuln/cmd/govulncheck@latest

292
README.md
View File

@ -3,7 +3,11 @@
[![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 and OpenSearch, written in Go.
## Supported Versions
We support all currently supported versions of Elasticsearch and OpenSearch. This project will make reasonable attempts to maintain compatibility with previous versions but considerations will be made for code maintainability and favoring supported versions. Where Elasticsearch and OpenSearch diverge, this project will make reasonable attempts to maintain compatibility with both. Some collectors may only be compatible with one or the other.
### Installation
@ -48,36 +52,43 @@ Below is the command line options summary:
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: `<proto>://<user>:<password>@<host>:<port>`. E.G., `http://admin:pass@localhost:9200`. Special characters in the user credentials need to be URL-encoded. | <http://localhost:9200> |
| 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. | |
| es.client-cert | 1.0.2 | Path to PEM file that contains the corresponding cert for the private key to connect to Elasticsearch. | |
| es.clusterinfo.interval | 1.1.0rc1 | Cluster info update interval for the cluster label | 5m |
| 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. | |
| Argument | Introduced in Version | Description | Default |
| ----------------------- | --------------------- |---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ----------- |
| collector.clustersettings| 1.6.0 | If true, query stats for cluster settings (As of v1.6.0, this flag has replaced "es.cluster_settings"). | false |
| es.uri | 1.0.2 | Address (host and port) of the Elasticsearch node we should connect to **when running in single-target mode**. Leave empty (the default) when you want to run the exporter only as a multi-target `/probe` endpoint. When basic auth is needed, specify as: `<proto>://<user>:<password>@<host>:<port>`. 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.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.ilm | 1.6.0 | If true, query index lifecycle policies for indices in the cluster.
| es.shards | 1.0.3rc1 | If true, query stats for all indices in the cluster, including shard-level stats (implies `es.indices=true`). | false |
| collector.snapshots | 1.0.4rc1 | If true, query stats for the cluster snapshots. (As of v1.7.0, this flag has replaced "es.snapshots"). | false |
| collector.health-report | 1.10.0 | If true, query the health report (requires elasticsearch 8.7.0 or later) | 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. | |
| es.client-cert | 1.0.2 | Path to PEM file that contains the corresponding cert for the private key to connect to Elasticsearch. | |
| es.clusterinfo.interval | 1.1.0rc1 | Cluster info update interval for the cluster label | 5m |
| 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. | |
| config.file | 1.10.0 | Path to a YAML configuration file that defines `auth_modules:` used by the `/probe` multi-target endpoint. Leave unset when not using multi-target mode. | |
| version | 1.0.2 | Show version info on stdout and exit. | |
Commandline parameters start with a single `-` for versions less than `1.1.0rc1`.
For versions greater than `1.1.0rc1`, commandline parameters are specified with `--`.
The API key used to connect can be set with the `ES_API_KEY` environment variable.
#### Logging
Logging by the exporter is handled by the `log/slog` package. The output format can be customized with the `--log.format` flag which defaults to logfmt. The log level can be set with the `--log.level` flag which defaults to info. The output can be set to either stdout (default) or stderr with the `--log.output` flag.
#### Elasticsearch 7.x security privileges
Username and password can be passed either directly in the URI or through the `ES_USERNAME` and `ES_PASSWORD` environment variables.
@ -87,14 +98,14 @@ ES 7.x supports RBACs. The following security privileges are required for the el
Setting | Privilege Required | Description
:---- | :---- | :----
collector.clustersettings| `cluster` `monitor` |
exporter defaults | `cluster` `monitor` | All cluster read-only operations, like cluster health and state, hot threads, node info, node and cluster stats, and pending cluster tasks. |
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`
collector.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 | `manage_slm`
es.data_stream | `monitor` or `manage` (per index or `*`) |
Further Information
@ -103,167 +114,70 @@ Further Information
- [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)
### Multi-Target Scraping (beta)
From v2.X the exporter exposes `/probe` allowing one running instance to scrape many clusters.
Supported `auth_module` types:
| type | YAML fields | Injected into request |
| ---------- | ----------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
| `userpass` | `userpass.username`, `userpass.password`, optional `options:` map | Sets HTTP basic-auth header, appends `options` as query parameters |
| `apikey` | `apikey:` Base64 API-Key string, optional `options:` map | Adds `Authorization: ApiKey …` header, appends `options` |
| `aws` | `aws.region`, optional `aws.role_arn`, optional `options:` map | Uses AWS SigV4 signing transport for HTTP(S) requests, appends `options` |
| `tls` | `tls.ca_file`, `tls.cert_file`, `tls.key_file` | Uses client certificate authentication via TLS; cannot be mixed with other auth types |
Example config:
```yaml
# exporter-config.yml
auth_modules:
prod_basic:
type: userpass
userpass:
username: metrics
password: s3cr3t
staging_key:
type: apikey
apikey: "bXk6YXBpa2V5Ig==" # base64 id:key
options:
sslmode: disable
```
Run exporter:
```bash
./elasticsearch_exporter --config.file=exporter-config.yml
```
Prometheus scrape_config:
```yaml
- job_name: es
metrics_path: /probe
params:
auth_module: [staging_key]
static_configs:
- targets: ["https://es-stage:9200"]
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: exporter:9114
```
Notes:
- `/metrics` serves a single, process-wide registry and is intended for single-target mode.
- `/probe` creates a fresh registry per scrape for the given `target` allowing multi-target scraping.
- Any `options:` under an auth module will be appended as URL query parameters to the target URL.
- The `tls` auth module (client certificate authentication) is intended for selfmanaged Elasticsearch/OpenSearch deployments. Amazon OpenSearch Service typically authenticates at the domain edge with IAM/SigV4 and does not support client certificate authentication; use the `aws` auth module instead when scraping Amazon OpenSearch Service domains.
### 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_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_creation_timestamp_seconds | gauge | 1 | Timestamp of the index creation in seconds |
| 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 |
See the [metrics documentation](metrics.md)
### Alerts & Recording Rules
@ -295,10 +209,6 @@ Then transferred this repository to the Prometheus Community in May 2021.
This package was originally created and maintained by [Eric Richardson](https://github.com/ewr),
who transferred this repository to us in January 2017.
Maintainers of this repository:
- Christoph Oelmüller <christoph.oelmueller@justwatch.com> @zwopir
Please refer to the Git commit log for a complete list of contributors.
## Contributing

View File

@ -1 +1 @@
1.7.0
1.10.0

View File

@ -1,4 +1,4 @@
// Copyright 2021 The Prometheus Authors
// Copyright 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
@ -17,12 +17,11 @@ import (
"encoding/json"
"fmt"
"io"
"log/slog"
"net/http"
"net/url"
"path"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/prometheus/client_golang/prometheus"
)
@ -46,7 +45,7 @@ type clusterHealthStatusMetric struct {
// ClusterHealth type defines the collector struct
type ClusterHealth struct {
logger log.Logger
logger *slog.Logger
client *http.Client
url *url.URL
@ -55,7 +54,7 @@ type ClusterHealth struct {
}
// NewClusterHealth returns a new Collector exposing ClusterHealth stats.
func NewClusterHealth(logger log.Logger, client *http.Client, url *url.URL) *ClusterHealth {
func NewClusterHealth(logger *slog.Logger, client *http.Client, url *url.URL) *ClusterHealth {
subsystem := "cluster_health"
return &ClusterHealth{
@ -225,8 +224,8 @@ func (c *ClusterHealth) fetchAndDecodeClusterHealth() (clusterHealthResponse, er
defer func() {
err = res.Body.Close()
if err != nil {
level.Warn(c.logger).Log(
"msg", "failed to close http.Client",
c.logger.Warn(
"failed to close http.Client",
"err", err,
)
}
@ -252,8 +251,8 @@ func (c *ClusterHealth) fetchAndDecodeClusterHealth() (clusterHealthResponse, er
func (c *ClusterHealth) Collect(ch chan<- prometheus.Metric) {
clusterHealthResp, err := c.fetchAndDecodeClusterHealth()
if err != nil {
level.Warn(c.logger).Log(
"msg", "failed to fetch and decode cluster health",
c.logger.Warn(
"failed to fetch and decode cluster health",
"err", err,
)
return

View File

@ -1,4 +1,4 @@
// Copyright 2021 The Prometheus Authors
// Copyright 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

View File

@ -1,4 +1,4 @@
// Copyright 2021 The Prometheus Authors
// Copyright 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
@ -22,8 +22,8 @@ import (
"strings"
"testing"
"github.com/go-kit/log"
"github.com/prometheus/client_golang/prometheus/testutil"
"github.com/prometheus/common/promslog"
)
func TestClusterHealth(t *testing.T) {
@ -189,7 +189,7 @@ func TestClusterHealth(t *testing.T) {
t.Fatal(err)
}
c := NewClusterHealth(log.NewNopLogger(), http.DefaultClient, u)
c := NewClusterHealth(promslog.NewNopLogger(), http.DefaultClient, u)
if err != nil {
t.Fatal(err)
}

View File

@ -1,4 +1,4 @@
// Copyright 2022 The Prometheus Authors
// Copyright 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
@ -17,11 +17,11 @@ import (
"context"
"encoding/json"
"io"
"log/slog"
"net/http"
"net/url"
"github.com/blang/semver/v4"
"github.com/go-kit/log"
"github.com/prometheus/client_golang/prometheus"
)
@ -30,12 +30,12 @@ func init() {
}
type ClusterInfoCollector struct {
logger log.Logger
logger *slog.Logger
u *url.URL
hc *http.Client
}
func NewClusterInfo(logger log.Logger, u *url.URL, hc *http.Client) (Collector, error) {
func NewClusterInfo(logger *slog.Logger, u *url.URL, hc *http.Client) (Collector, error) {
return &ClusterInfoCollector{
logger: logger,
u: u,
@ -77,7 +77,7 @@ type VersionInfo struct {
LuceneVersion semver.Version `json:"lucene_version"`
}
func (c *ClusterInfoCollector) Update(ctx context.Context, ch chan<- prometheus.Metric) error {
func (c *ClusterInfoCollector) Update(_ context.Context, ch chan<- prometheus.Metric) error {
resp, err := c.hc.Get(c.u.String())
if err != nil {
return err

View File

@ -1,4 +1,4 @@
// Copyright 2023 The Prometheus Authors
// Copyright 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
@ -22,8 +22,8 @@ import (
"strings"
"testing"
"github.com/go-kit/log"
"github.com/prometheus/client_golang/prometheus/testutil"
"github.com/prometheus/common/promslog"
)
func TestClusterInfo(t *testing.T) {
@ -80,7 +80,7 @@ func TestClusterInfo(t *testing.T) {
t.Fatal(err)
}
c, err := NewClusterInfo(log.NewNopLogger(), u, http.DefaultClient)
c, err := NewClusterInfo(promslog.NewNopLogger(), u, http.DefaultClient)
if err != nil {
t.Fatal(err)
}

View File

@ -1,4 +1,4 @@
// Copyright 2021 The Prometheus Authors
// Copyright 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
@ -18,13 +18,12 @@ import (
"encoding/json"
"fmt"
"io"
"log/slog"
"net/http"
"net/url"
"strconv"
"strings"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/imdario/mergo"
"github.com/prometheus/client_golang/prometheus"
)
@ -34,12 +33,12 @@ func init() {
}
type ClusterSettingsCollector struct {
logger log.Logger
logger *slog.Logger
u *url.URL
hc *http.Client
}
func NewClusterSettings(logger log.Logger, u *url.URL, hc *http.Client) (Collector, error) {
func NewClusterSettings(logger *slog.Logger, u *url.URL, hc *http.Client) (Collector, error) {
return &ClusterSettingsCollector{
logger: logger,
u: u,
@ -141,9 +140,9 @@ type clusterSettingsDisk struct {
// 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"`
FloodStage interface{} `json:"flood_stage"`
High interface{} `json:"high"`
Low interface{} `json:"low"`
}
func (c *ClusterSettingsCollector) Update(ctx context.Context, ch chan<- prometheus.Metric) error {
@ -152,7 +151,7 @@ func (c *ClusterSettingsCollector) Update(ctx context.Context, ch chan<- prometh
q.Set("include_defaults", "true")
u.RawQuery = q.Encode()
req, err := http.NewRequestWithContext(ctx, "GET", u.String(), nil)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil)
if err != nil {
return err
}
@ -223,80 +222,110 @@ func (c *ClusterSettingsCollector) Update(ctx context.Context, ch chan<- prometh
)
// Watermark bytes or ratio metrics
if strings.HasSuffix(merged.Cluster.Routing.Allocation.Disk.Watermark.High, "b") {
flooodStageBytes, err := getValueInBytes(merged.Cluster.Routing.Allocation.Disk.Watermark.FloodStage)
if err != nil {
level.Error(c.logger).Log("msg", "failed to parse flood_stage bytes", "err", err)
watermarkFlood, err := parseWatermarkValue(merged.Cluster.Routing.Allocation.Disk.Watermark.FloodStage)
if err != nil {
c.logger.Error("failed to parse flood stage watermark", "err", err)
} else {
if strings.HasSuffix(watermarkFlood, "b") {
floodStageBytes, err := getValueInBytes(watermarkFlood)
if err != nil {
c.logger.Error("failed to parse flood_stage bytes", "err", err)
} else {
ch <- prometheus.MustNewConstMetric(
clusterSettingsDesc["floodStageBytes"],
prometheus.GaugeValue,
floodStageBytes,
)
}
} else {
ch <- prometheus.MustNewConstMetric(
clusterSettingsDesc["floodStageBytes"],
prometheus.GaugeValue,
flooodStageBytes,
)
floodStageRatio, err := getValueAsRatio(watermarkFlood)
if err != nil {
c.logger.Error("failed to parse flood_stage ratio", "err", err)
} else {
ch <- prometheus.MustNewConstMetric(
clusterSettingsDesc["floodStageRatio"],
prometheus.GaugeValue,
floodStageRatio,
)
}
}
highBytes, err := getValueInBytes(merged.Cluster.Routing.Allocation.Disk.Watermark.High)
if err != nil {
level.Error(c.logger).Log("msg", "failed to parse high bytes", "err", err)
} else {
ch <- prometheus.MustNewConstMetric(
clusterSettingsDesc["highBytes"],
prometheus.GaugeValue,
highBytes,
)
}
lowBytes, err := getValueInBytes(merged.Cluster.Routing.Allocation.Disk.Watermark.Low)
if err != nil {
level.Error(c.logger).Log("msg", "failed to parse low bytes", "err", err)
} else {
ch <- prometheus.MustNewConstMetric(
clusterSettingsDesc["lowBytes"],
prometheus.GaugeValue,
lowBytes,
)
}
return nil
}
// Watermark ratio metrics
floodRatio, err := getValueAsRatio(merged.Cluster.Routing.Allocation.Disk.Watermark.FloodStage)
watermarkHigh, err := parseWatermarkValue(merged.Cluster.Routing.Allocation.Disk.Watermark.High)
if err != nil {
level.Error(c.logger).Log("msg", "failed to parse flood_stage ratio", "err", err)
c.logger.Error("failed to parse high watermark", "err", err)
} else {
ch <- prometheus.MustNewConstMetric(
clusterSettingsDesc["floodStageRatio"],
prometheus.GaugeValue,
floodRatio,
)
if strings.HasSuffix(watermarkHigh, "b") {
highBytes, err := getValueInBytes(watermarkHigh)
if err != nil {
c.logger.Error("failed to parse high bytes", "err", err)
} else {
ch <- prometheus.MustNewConstMetric(
clusterSettingsDesc["highBytes"],
prometheus.GaugeValue,
highBytes,
)
}
} else {
highRatio, err := getValueAsRatio(watermarkHigh)
if err != nil {
c.logger.Error("failed to parse high ratio", "err", err)
} else {
ch <- prometheus.MustNewConstMetric(
clusterSettingsDesc["highRatio"],
prometheus.GaugeValue,
highRatio,
)
}
}
}
highRatio, err := getValueAsRatio(merged.Cluster.Routing.Allocation.Disk.Watermark.High)
watermarkLow, err := parseWatermarkValue(merged.Cluster.Routing.Allocation.Disk.Watermark.Low)
if err != nil {
level.Error(c.logger).Log("msg", "failed to parse high ratio", "err", err)
c.logger.Error("failed to parse low watermark", "err", err)
} else {
ch <- prometheus.MustNewConstMetric(
clusterSettingsDesc["highRatio"],
prometheus.GaugeValue,
highRatio,
)
}
lowRatio, err := getValueAsRatio(merged.Cluster.Routing.Allocation.Disk.Watermark.Low)
if err != nil {
level.Error(c.logger).Log("msg", "failed to parse low ratio", "err", err)
} else {
ch <- prometheus.MustNewConstMetric(
clusterSettingsDesc["lowRatio"],
prometheus.GaugeValue,
lowRatio,
)
if strings.HasSuffix(watermarkLow, "b") {
lowBytes, err := getValueInBytes(watermarkLow)
if err != nil {
c.logger.Error("failed to parse low bytes", "err", err)
} else {
ch <- prometheus.MustNewConstMetric(
clusterSettingsDesc["lowBytes"],
prometheus.GaugeValue,
lowBytes,
)
}
} else {
lowRatio, err := getValueAsRatio(watermarkLow)
if err != nil {
c.logger.Error("failed to parse low ratio", "err", err)
} else {
ch <- prometheus.MustNewConstMetric(
clusterSettingsDesc["lowRatio"],
prometheus.GaugeValue,
lowRatio,
)
}
}
}
return nil
}
func parseWatermarkValue(value interface{}) (string, error) {
switch v := value.(type) {
case string:
return v, nil
case map[string]interface{}:
if val, ok := v["value"].(string); ok {
return val, nil
}
return "", fmt.Errorf("unexpected structure in watermark value: %v", v)
default:
return "", fmt.Errorf("unsupported type for watermark value: %T", v)
}
}
func getValueInBytes(value string) (float64, error) {
type UnitValue struct {
unit string

View File

@ -1,4 +1,4 @@
// Copyright 2021 The Prometheus Authors
// Copyright 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
@ -14,7 +14,6 @@
package collector
import (
"context"
"io"
"net/http"
"net/http/httptest"
@ -23,22 +22,10 @@ import (
"strings"
"testing"
"github.com/go-kit/log"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/testutil"
"github.com/prometheus/common/promslog"
)
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
@ -127,6 +114,30 @@ 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
`,
},
{
name: "8.9.1-persistent-watermark-percent",
file: "../fixtures/settings-8.9.1-watermark.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_ratio Flood stage watermark as a ratio.
# TYPE elasticsearch_clustersettings_allocation_watermark_flood_stage_ratio gauge
elasticsearch_clustersettings_allocation_watermark_flood_stage_ratio 0.96
# 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.92
# 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.88
`,
},
}
@ -149,7 +160,7 @@ elasticsearch_clustersettings_allocation_watermark_low_bytes 5.24288e+07
t.Fatal(err)
}
c, err := NewClusterSettings(log.NewNopLogger(), u, http.DefaultClient)
c, err := NewClusterSettings(promslog.NewNopLogger(), u, http.DefaultClient)
if err != nil {
t.Fatal(err)
}

View File

@ -1,4 +1,4 @@
// Copyright 2022 The Prometheus Authors
// Copyright 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
@ -18,14 +18,13 @@ import (
"context"
"errors"
"fmt"
"log/slog"
"net/http"
"net/url"
"sync"
"time"
"github.com/alecthomas/kingpin/v2"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/prometheus/client_golang/prometheus"
)
@ -37,7 +36,7 @@ const (
defaultDisabled = false
)
type factoryFunc func(logger log.Logger, u *url.URL, hc *http.Client) (Collector, error)
type factoryFunc func(logger *slog.Logger, u *url.URL, hc *http.Client) (Collector, error)
var (
factories = make(map[string]factoryFunc)
@ -90,7 +89,7 @@ func registerCollector(name string, isDefaultEnabled bool, createFunc factoryFun
type ElasticsearchCollector struct {
Collectors map[string]Collector
logger log.Logger
logger *slog.Logger
esURL *url.URL
httpClient *http.Client
}
@ -98,7 +97,7 @@ type ElasticsearchCollector struct {
type Option func(*ElasticsearchCollector) error
// NewElasticsearchCollector creates a new ElasticsearchCollector
func NewElasticsearchCollector(logger log.Logger, filters []string, options ...Option) (*ElasticsearchCollector, error) {
func NewElasticsearchCollector(logger *slog.Logger, filters []string, options ...Option) (*ElasticsearchCollector, error) {
e := &ElasticsearchCollector{logger: logger}
// Apply options to customize the collector
for _, o := range options {
@ -128,7 +127,7 @@ func NewElasticsearchCollector(logger log.Logger, filters []string, options ...O
if collector, ok := initiatedCollectors[key]; ok {
collectors[key] = collector
} else {
collector, err := factories[key](log.With(logger, "collector", key), e.esURL, e.httpClient)
collector, err := factories[key](logger.With("collector", key), e.esURL, e.httpClient)
if err != nil {
return nil, err
}
@ -176,7 +175,7 @@ func (e ElasticsearchCollector) Collect(ch chan<- prometheus.Metric) {
wg.Wait()
}
func execute(ctx context.Context, name string, c Collector, ch chan<- prometheus.Metric, logger log.Logger) {
func execute(ctx context.Context, name string, c Collector, ch chan<- prometheus.Metric, logger *slog.Logger) {
begin := time.Now()
err := c.Update(ctx, ch)
duration := time.Since(begin)
@ -184,13 +183,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)
logger.Debug("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)
logger.Warn("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())
logger.Debug("collector succeeded", "name", name, "duration_seconds", duration.Seconds())
success = 1
}
ch <- prometheus.MustNewConstMetric(scrapeDurationDesc, prometheus.GaugeValue, duration.Seconds(), name)

View File

@ -1,4 +1,4 @@
// Copyright 2021 The Prometheus Authors
// Copyright 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
@ -13,12 +13,24 @@
package collector
var testElasticsearchVersions = []string{
"5.4.2",
"5.6.16",
"6.5.4",
"6.8.8",
"7.3.0",
"7.6.2",
"7.13.1",
import (
"context"
"github.com/prometheus/client_golang/prometheus"
)
// wrapCollector is a util to let you test your Collector implementation.
//
// Use this with prometheus/client_golang/prometheus/testutil to test metric output, for example:
//
// testutil.CollectAndCompare(wrapCollector{c}, strings.NewReader(want))
type wrapCollector struct {
c Collector
}
func (w wrapCollector) Describe(_ chan<- *prometheus.Desc) {
}
func (w wrapCollector) Collect(ch chan<- prometheus.Metric) {
w.c.Update(context.Background(), ch)
}

View File

@ -1,4 +1,4 @@
// Copyright 2022 The Prometheus Authors
// Copyright 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
@ -14,142 +14,106 @@
package collector
import (
"context"
"encoding/json"
"fmt"
"io"
"log/slog"
"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}
}
dataStreamBackingIndicesTotal = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "data_stream", "backing_indices_total"),
"Number of backing indices",
[]string{"data_stream"},
nil,
)
dataStreamStoreSizeBytes = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "data_stream", "store_size_bytes"),
"Store size of data stream",
[]string{"data_stream"},
nil,
)
)
func init() {
registerCollector("data-stream", defaultDisabled, NewDataStream)
}
// DataStream Information Struct
type DataStream struct {
logger log.Logger
client *http.Client
url *url.URL
dataStreamMetrics []*dataStreamMetric
logger *slog.Logger
hc *http.Client
u *url.URL
}
// NewDataStream defines DataStream Prometheus metrics
func NewDataStream(logger log.Logger, client *http.Client, url *url.URL) *DataStream {
func NewDataStream(logger *slog.Logger, u *url.URL, hc *http.Client) (Collector, error) {
return &DataStream{
logger: logger,
client: client,
url: url,
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,
},
},
}
hc: hc,
u: u,
}, nil
}
// Describe adds DataStream metrics descriptions
func (ds *DataStream) Describe(ch chan<- *prometheus.Desc) {
for _, metric := range ds.dataStreamMetrics {
ch <- metric.Desc
}
// 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"`
}
func (ds *DataStream) fetchAndDecodeDataStreamStats() (DataStreamStatsResponse, error) {
// 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"`
}
func (ds *DataStream) Update(ctx context.Context, ch chan<- prometheus.Metric) error {
var dsr DataStreamStatsResponse
u := *ds.url
u.Path = path.Join(u.Path, "/_data_stream/*/_stats")
res, err := ds.client.Get(u.String())
u := ds.u.ResolveReference(&url.URL{Path: "/_data_stream/*/_stats"})
resp, err := getURL(ctx, ds.hc, ds.logger, 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)
return 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)
if err := json.Unmarshal(resp, &dsr); err != nil {
return err
}
bts, err := io.ReadAll(res.Body)
if err != nil {
return dsr, err
}
for _, dataStream := range dsr.DataStreamStats {
fmt.Printf("Metric: %+v", dataStream)
if err := json.Unmarshal(bts, &dsr); err != nil {
return dsr, err
}
return dsr, nil
}
// Collect gets DataStream metric values
func (ds *DataStream) Collect(ch chan<- prometheus.Metric) {
dataStreamStatsResp, err := ds.fetchAndDecodeDataStreamStats()
if err != nil {
level.Warn(ds.logger).Log(
"msg", "failed to fetch and decode data stream stats",
"err", err,
ch <- prometheus.MustNewConstMetric(
dataStreamBackingIndicesTotal,
prometheus.CounterValue,
float64(dataStream.BackingIndices),
dataStream.DataStream,
)
ch <- prometheus.MustNewConstMetric(
dataStreamStoreSizeBytes,
prometheus.CounterValue,
float64(dataStream.StoreSizeBytes),
dataStream.DataStream,
)
return
}
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)...,
)
}
}
return nil
}

View File

@ -1,38 +0,0 @@
// 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"`
}

View File

@ -1,4 +1,4 @@
// Copyright 2022 The Prometheus Authors
// Copyright 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
@ -22,12 +22,11 @@ import (
"strings"
"testing"
"github.com/go-kit/log"
"github.com/prometheus/client_golang/prometheus/testutil"
"github.com/prometheus/common/promslog"
)
func TestDataStream(t *testing.T) {
tests := []struct {
name string
file string
@ -65,12 +64,12 @@ func TestDataStream(t *testing.T) {
t.Fatal(err)
}
c := NewDataStream(log.NewNopLogger(), http.DefaultClient, u)
c, err := NewDataStream(promslog.NewNopLogger(), u, http.DefaultClient)
if err != nil {
t.Fatal(err)
}
if err := testutil.CollectAndCompare(c, strings.NewReader(tt.want)); err != nil {
if err := testutil.CollectAndCompare(wrapCollector{c}, strings.NewReader(tt.want)); err != nil {
t.Fatal(err)
}
})

472
collector/health_report.go Normal file
View File

@ -0,0 +1,472 @@
// Copyright 2025 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 (
"context"
"encoding/json"
"log/slog"
"net/http"
"net/url"
"github.com/prometheus/client_golang/prometheus"
)
var (
statusColors = []string{"green", "yellow", "red"}
defaultHealthReportLabels = []string{"cluster"}
)
var (
healthReportTotalRepositories = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "health_report", "total_repositories"),
"The number of snapshot repositories",
defaultHealthReportLabels, nil,
)
healthReportMaxShardsInClusterData = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "health_report", "max_shards_in_cluster_data"),
"The number of maximum shards in a cluster",
defaultHealthReportLabels, nil,
)
healthReportMaxShardsInClusterFrozen = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "health_report", "max_shards_in_cluster_frozen"),
"The number of maximum frozen shards in a cluster",
defaultHealthReportLabels, nil,
)
healthReportRestartingReplicas = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "health_report", "restarting_replicas"),
"The number of restarting replica shards",
defaultHealthReportLabels, nil,
)
healthReportCreatingPrimaries = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "health_report", "creating_primaries"),
"The number of creating primary shards",
defaultHealthReportLabels, nil,
)
healthReportInitializingReplicas = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "health_report", "initializing_replicas"),
"The number of initializing replica shards",
defaultHealthReportLabels, nil,
)
healthReportUnassignedReplicas = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "health_report", "unassigned_replicas"),
"The number of unassigned replica shards",
defaultHealthReportLabels, nil,
)
healthReportStartedPrimaries = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "health_report", "started_primaries"),
"The number of started primary shards",
defaultHealthReportLabels, nil,
)
healthReportRestartingPrimaries = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "health_report", "restarting_primaries"),
"The number of restarting primary shards",
defaultHealthReportLabels, nil,
)
healthReportInitializingPrimaries = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "health_report", "initializing_primaries"),
"The number of initializing primary shards",
defaultHealthReportLabels, nil,
)
healthReportCreatingReplicas = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "health_report", "creating_replicas"),
"The number of creating replica shards",
defaultHealthReportLabels, nil,
)
healthReportStartedReplicas = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "health_report", "started_replicas"),
"The number of started replica shards",
defaultHealthReportLabels, nil,
)
healthReportUnassignedPrimaries = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "health_report", "unassigned_primaries"),
"The number of unassigned primary shards",
defaultHealthReportLabels, nil,
)
healthReportSlmPolicies = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "health_report", "slm_policies"),
"The number of SLM policies",
defaultHealthReportLabels, nil,
)
healthReportIlmPolicies = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "health_report", "ilm_policies"),
"The number of ILM Policies",
defaultHealthReportLabels, nil,
)
healthReportIlmStagnatingIndices = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "health_report", "ilm_stagnating_indices"),
"The number of stagnating indices",
defaultHealthReportLabels, nil,
)
healthReportStatus = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "health_report", "status"),
"Overall cluster status",
[]string{"cluster", "color"}, nil,
)
healthReportMasterIsStableStatus = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "health_report", "master_is_stable_status"),
"Master is stable status",
[]string{"cluster", "color"}, nil,
)
healthReportRepositoryIntegrityStatus = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "health_report", "repository_integrity_status"),
"Repository integrity status",
[]string{"cluster", "color"}, nil,
)
healthReportDiskStatus = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "health_report", "disk_status"),
"Disk status",
[]string{"cluster", "color"}, nil,
)
healthReportShardsCapacityStatus = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "health_report", "shards_capacity_status"),
"Shards capacity status",
[]string{"cluster", "color"}, nil,
)
healthReportShardsAvailabiltystatus = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "health_report", "shards_availabilty_status"),
"Shards availabilty status",
[]string{"cluster", "color"}, nil,
)
healthReportDataStreamLifecycleStatus = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "health_report", "data_stream_lifecycle_status"),
"Data stream lifecycle status",
[]string{"cluster", "color"}, nil,
)
healthReportSlmStatus = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "health_report", "slm_status"),
"SLM status",
[]string{"cluster", "color"}, nil,
)
healthReportIlmStatus = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "health_report", "ilm_status"),
"ILM status",
[]string{"cluster", "color"}, nil,
)
)
func init() {
registerCollector("health-report", defaultDisabled, NewHealthReport)
}
type HealthReport struct {
logger *slog.Logger
client *http.Client
url *url.URL
}
func NewHealthReport(logger *slog.Logger, url *url.URL, client *http.Client) (Collector, error) {
return &HealthReport{
logger: logger,
client: client,
url: url,
}, nil
}
type HealthReportResponse struct {
ClusterName string `json:"cluster_name"`
Status string `json:"status"`
Indicators HealthReportIndicators `json:"indicators"`
}
type HealthReportIndicators struct {
MasterIsStable HealthReportMasterIsStable `json:"master_is_stable"`
RepositoryIntegrity HealthReportRepositoryIntegrity `json:"repository_integrity"`
Disk HealthReportDisk `json:"disk"`
ShardsCapacity HealthReportShardsCapacity `json:"shards_capacity"`
ShardsAvailability HealthReportShardsAvailability `json:"shards_availability"`
DataStreamLifecycle HealthReportDataStreamLifecycle `json:"data_stream_lifecycle"`
Slm HealthReportSlm `json:"slm"`
Ilm HealthReportIlm `json:"ilm"`
}
type HealthReportMasterIsStable struct {
Status string `json:"status"`
Symptom string `json:"symptom"`
Details HealthReportMasterIsStableDetails `json:"details"`
}
type HealthReportMasterIsStableDetails struct {
CurrentMaster HealthReportMasterIsStableDetailsNode `json:"current_master"`
RecentMasters []HealthReportMasterIsStableDetailsNode `json:"recent_masters"`
}
type HealthReportMasterIsStableDetailsNode struct {
NodeID string `json:"node_id"`
Name string `json:"name"`
}
type HealthReportRepositoryIntegrity struct {
Status string `json:"status"`
Symptom string `json:"symptom"`
Details HealthReportRepositoriyIntegrityDetails `json:"details"`
}
type HealthReportRepositoriyIntegrityDetails struct {
TotalRepositories int `json:"total_repositories"`
}
type HealthReportDisk struct {
Status string `json:"status"`
Symptom string `json:"symptom"`
Details HealthReportDiskDetails `json:"details"`
}
type HealthReportDiskDetails struct {
IndicesWithReadonlyBlock int `json:"indices_with_readonly_block"`
NodesWithEnoughDiskSpace int `json:"nodes_with_enough_disk_space"`
NodesWithUnknownDiskStatus int `json:"nodes_with_unknown_disk_status"`
NodesOverHighWatermark int `json:"nodes_over_high_watermark"`
NodesOverFloodStageWatermark int `json:"nodes_over_flood_stage_watermark"`
}
type HealthReportShardsCapacity struct {
Status string `json:"status"`
Symptom string `json:"symptom"`
Details HealthReportShardsCapacityDetails `json:"details"`
}
type HealthReportShardsCapacityDetails struct {
Data HealthReportShardsCapacityDetailsMaxShards `json:"data"`
Frozen HealthReportShardsCapacityDetailsMaxShards `json:"frozen"`
}
type HealthReportShardsCapacityDetailsMaxShards struct {
MaxShardsInCluster int `json:"max_shards_in_cluster"`
}
type HealthReportShardsAvailability struct {
Status string `json:"status"`
Symptom string `json:"symptom"`
Details HealthReportShardsAvailabilityDetails `json:"details"`
}
type HealthReportShardsAvailabilityDetails struct {
RestartingReplicas int `json:"restarting_replicas"`
CreatingPrimaries int `json:"creating_primaries"`
InitializingReplicas int `json:"initializing_replicas"`
UnassignedReplicas int `json:"unassigned_replicas"`
StartedPrimaries int `json:"started_primaries"`
RestartingPrimaries int `json:"restarting_primaries"`
InitializingPrimaries int `json:"initializing_primaries"`
CreatingReplicas int `json:"creating_replicas"`
StartedReplicas int `json:"started_replicas"`
UnassignedPrimaries int `json:"unassigned_primaries"`
}
type HealthReportDataStreamLifecycle struct {
Status string `json:"status"`
Symptom string `json:"symptom"`
}
type HealthReportSlm struct {
Status string `json:"status"`
Symptom string `json:"symptom"`
Details HealthReportSlmDetails `json:"details"`
}
type HealthReportSlmDetails struct {
SlmStatus string `json:"slm_status"`
Policies int `json:"policies"`
}
type HealthReportIlm struct {
Status string `json:"status"`
Symptom string `json:"symptom"`
Details HealthReportIlmDetails `json:"details"`
}
type HealthReportIlmDetails struct {
Policies int `json:"policies"`
StagnatingIndices int `json:"stagnating_indices"`
IlmStatus string `json:"ilm_status"`
}
func statusValue(value string, color string) float64 {
if value == color {
return 1
}
return 0
}
func (c *HealthReport) Update(ctx context.Context, ch chan<- prometheus.Metric) error {
u := c.url.ResolveReference(&url.URL{Path: "/_health_report"})
var healthReportResponse HealthReportResponse
resp, err := getURL(ctx, c.client, c.logger, u.String())
if err != nil {
return err
}
err = json.Unmarshal(resp, &healthReportResponse)
if err != nil {
return err
}
ch <- prometheus.MustNewConstMetric(
healthReportTotalRepositories,
prometheus.GaugeValue,
float64(healthReportResponse.Indicators.RepositoryIntegrity.Details.TotalRepositories),
healthReportResponse.ClusterName,
)
ch <- prometheus.MustNewConstMetric(
healthReportMaxShardsInClusterData,
prometheus.GaugeValue,
float64(healthReportResponse.Indicators.ShardsCapacity.Details.Data.MaxShardsInCluster),
healthReportResponse.ClusterName,
)
ch <- prometheus.MustNewConstMetric(
healthReportMaxShardsInClusterFrozen,
prometheus.GaugeValue,
float64(healthReportResponse.Indicators.ShardsCapacity.Details.Frozen.MaxShardsInCluster),
healthReportResponse.ClusterName,
)
ch <- prometheus.MustNewConstMetric(
healthReportRestartingReplicas,
prometheus.GaugeValue,
float64(healthReportResponse.Indicators.ShardsAvailability.Details.RestartingReplicas),
healthReportResponse.ClusterName,
)
ch <- prometheus.MustNewConstMetric(
healthReportCreatingPrimaries,
prometheus.GaugeValue,
float64(healthReportResponse.Indicators.ShardsAvailability.Details.CreatingPrimaries),
healthReportResponse.ClusterName,
)
ch <- prometheus.MustNewConstMetric(
healthReportInitializingReplicas,
prometheus.GaugeValue,
float64(healthReportResponse.Indicators.ShardsAvailability.Details.InitializingReplicas),
healthReportResponse.ClusterName,
)
ch <- prometheus.MustNewConstMetric(
healthReportUnassignedReplicas,
prometheus.GaugeValue,
float64(healthReportResponse.Indicators.ShardsAvailability.Details.UnassignedReplicas),
healthReportResponse.ClusterName,
)
ch <- prometheus.MustNewConstMetric(
healthReportStartedPrimaries,
prometheus.GaugeValue,
float64(healthReportResponse.Indicators.ShardsAvailability.Details.StartedPrimaries),
healthReportResponse.ClusterName,
)
ch <- prometheus.MustNewConstMetric(
healthReportRestartingPrimaries,
prometheus.GaugeValue,
float64(healthReportResponse.Indicators.ShardsAvailability.Details.RestartingPrimaries),
healthReportResponse.ClusterName,
)
ch <- prometheus.MustNewConstMetric(
healthReportInitializingPrimaries,
prometheus.GaugeValue,
float64(healthReportResponse.Indicators.ShardsAvailability.Details.InitializingPrimaries),
healthReportResponse.ClusterName,
)
ch <- prometheus.MustNewConstMetric(
healthReportCreatingReplicas,
prometheus.GaugeValue,
float64(healthReportResponse.Indicators.ShardsAvailability.Details.CreatingReplicas),
healthReportResponse.ClusterName,
)
ch <- prometheus.MustNewConstMetric(
healthReportStartedReplicas,
prometheus.GaugeValue,
float64(healthReportResponse.Indicators.ShardsAvailability.Details.StartedReplicas),
healthReportResponse.ClusterName,
)
ch <- prometheus.MustNewConstMetric(
healthReportUnassignedPrimaries,
prometheus.GaugeValue,
float64(healthReportResponse.Indicators.ShardsAvailability.Details.UnassignedPrimaries),
healthReportResponse.ClusterName,
)
ch <- prometheus.MustNewConstMetric(
healthReportSlmPolicies,
prometheus.GaugeValue,
float64(healthReportResponse.Indicators.Slm.Details.Policies),
healthReportResponse.ClusterName,
)
ch <- prometheus.MustNewConstMetric(
healthReportIlmPolicies,
prometheus.GaugeValue,
float64(healthReportResponse.Indicators.Ilm.Details.Policies),
healthReportResponse.ClusterName,
)
ch <- prometheus.MustNewConstMetric(
healthReportIlmStagnatingIndices,
prometheus.GaugeValue,
float64(healthReportResponse.Indicators.Ilm.Details.StagnatingIndices),
healthReportResponse.ClusterName,
)
for _, color := range statusColors {
ch <- prometheus.MustNewConstMetric(
healthReportStatus,
prometheus.GaugeValue,
statusValue(healthReportResponse.Status, color),
healthReportResponse.ClusterName, color,
)
ch <- prometheus.MustNewConstMetric(
healthReportMasterIsStableStatus,
prometheus.GaugeValue,
statusValue(healthReportResponse.Indicators.MasterIsStable.Status, color),
healthReportResponse.ClusterName, color,
)
ch <- prometheus.MustNewConstMetric(
healthReportRepositoryIntegrityStatus,
prometheus.GaugeValue,
statusValue(healthReportResponse.Indicators.RepositoryIntegrity.Status, color),
healthReportResponse.ClusterName, color,
)
ch <- prometheus.MustNewConstMetric(
healthReportDiskStatus,
prometheus.GaugeValue,
statusValue(healthReportResponse.Indicators.Disk.Status, color),
healthReportResponse.ClusterName, color,
)
ch <- prometheus.MustNewConstMetric(
healthReportShardsCapacityStatus,
prometheus.GaugeValue,
statusValue(healthReportResponse.Indicators.ShardsCapacity.Status, color),
healthReportResponse.ClusterName, color,
)
ch <- prometheus.MustNewConstMetric(
healthReportShardsAvailabiltystatus,
prometheus.GaugeValue,
statusValue(healthReportResponse.Indicators.ShardsAvailability.Status, color),
healthReportResponse.ClusterName, color,
)
ch <- prometheus.MustNewConstMetric(
healthReportDataStreamLifecycleStatus,
prometheus.GaugeValue,
statusValue(healthReportResponse.Indicators.DataStreamLifecycle.Status, color),
healthReportResponse.ClusterName, color,
)
ch <- prometheus.MustNewConstMetric(
healthReportSlmStatus,
prometheus.GaugeValue,
statusValue(healthReportResponse.Indicators.Slm.Status, color),
healthReportResponse.ClusterName, color,
)
ch <- prometheus.MustNewConstMetric(
healthReportIlmStatus,
prometheus.GaugeValue,
statusValue(healthReportResponse.Indicators.Ilm.Status, color),
healthReportResponse.ClusterName, color,
)
}
return nil
}

View File

@ -0,0 +1,169 @@
// Copyright 2025 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 (
"io"
"net/http"
"net/http/httptest"
"net/url"
"os"
"strings"
"testing"
"github.com/prometheus/client_golang/prometheus/testutil"
"github.com/prometheus/common/promslog"
)
func TestHealthReport(t *testing.T) {
// Testcases created using:
// docker run -d -p 9200:9200 elasticsearch:VERSION
// curl -XPUT http://localhost:9200/twitter
// curl http://localhost:9200/_health_report
tests := []struct {
name string
file string
want string
}{
{
name: "8.7.0",
file: "../fixtures/healthreport/8.7.0.json",
want: `
# HELP elasticsearch_health_report_creating_primaries The number of creating primary shards
# TYPE elasticsearch_health_report_creating_primaries gauge
elasticsearch_health_report_creating_primaries{cluster="docker-cluster"} 0
# HELP elasticsearch_health_report_creating_replicas The number of creating replica shards
# TYPE elasticsearch_health_report_creating_replicas gauge
elasticsearch_health_report_creating_replicas{cluster="docker-cluster"} 0
# HELP elasticsearch_health_report_data_stream_lifecycle_status Data stream lifecycle status
# TYPE elasticsearch_health_report_data_stream_lifecycle_status gauge
elasticsearch_health_report_data_stream_lifecycle_status{cluster="docker-cluster",color="green"} 1
elasticsearch_health_report_data_stream_lifecycle_status{cluster="docker-cluster",color="red"} 0
elasticsearch_health_report_data_stream_lifecycle_status{cluster="docker-cluster",color="yellow"} 0
# HELP elasticsearch_health_report_disk_status Disk status
# TYPE elasticsearch_health_report_disk_status gauge
elasticsearch_health_report_disk_status{cluster="docker-cluster",color="green"} 1
elasticsearch_health_report_disk_status{cluster="docker-cluster",color="red"} 0
elasticsearch_health_report_disk_status{cluster="docker-cluster",color="yellow"} 0
# HELP elasticsearch_health_report_ilm_policies The number of ILM Policies
# TYPE elasticsearch_health_report_ilm_policies gauge
elasticsearch_health_report_ilm_policies{cluster="docker-cluster"} 17
# HELP elasticsearch_health_report_ilm_stagnating_indices The number of stagnating indices
# TYPE elasticsearch_health_report_ilm_stagnating_indices gauge
elasticsearch_health_report_ilm_stagnating_indices{cluster="docker-cluster"} 0
# HELP elasticsearch_health_report_ilm_status ILM status
# TYPE elasticsearch_health_report_ilm_status gauge
elasticsearch_health_report_ilm_status{cluster="docker-cluster",color="green"} 1
elasticsearch_health_report_ilm_status{cluster="docker-cluster",color="red"} 0
elasticsearch_health_report_ilm_status{cluster="docker-cluster",color="yellow"} 0
# HELP elasticsearch_health_report_initializing_primaries The number of initializing primary shards
# TYPE elasticsearch_health_report_initializing_primaries gauge
elasticsearch_health_report_initializing_primaries{cluster="docker-cluster"} 0
# HELP elasticsearch_health_report_initializing_replicas The number of initializing replica shards
# TYPE elasticsearch_health_report_initializing_replicas gauge
elasticsearch_health_report_initializing_replicas{cluster="docker-cluster"} 0
# HELP elasticsearch_health_report_master_is_stable_status Master is stable status
# TYPE elasticsearch_health_report_master_is_stable_status gauge
elasticsearch_health_report_master_is_stable_status{cluster="docker-cluster",color="green"} 1
elasticsearch_health_report_master_is_stable_status{cluster="docker-cluster",color="red"} 0
elasticsearch_health_report_master_is_stable_status{cluster="docker-cluster",color="yellow"} 0
# HELP elasticsearch_health_report_max_shards_in_cluster_data The number of maximum shards in a cluster
# TYPE elasticsearch_health_report_max_shards_in_cluster_data gauge
elasticsearch_health_report_max_shards_in_cluster_data{cluster="docker-cluster"} 13500
# HELP elasticsearch_health_report_max_shards_in_cluster_frozen The number of maximum frozen shards in a cluster
# TYPE elasticsearch_health_report_max_shards_in_cluster_frozen gauge
elasticsearch_health_report_max_shards_in_cluster_frozen{cluster="docker-cluster"} 9000
# HELP elasticsearch_health_report_repository_integrity_status Repository integrity status
# TYPE elasticsearch_health_report_repository_integrity_status gauge
elasticsearch_health_report_repository_integrity_status{cluster="docker-cluster",color="green"} 1
elasticsearch_health_report_repository_integrity_status{cluster="docker-cluster",color="red"} 0
elasticsearch_health_report_repository_integrity_status{cluster="docker-cluster",color="yellow"} 0
# HELP elasticsearch_health_report_restarting_primaries The number of restarting primary shards
# TYPE elasticsearch_health_report_restarting_primaries gauge
elasticsearch_health_report_restarting_primaries{cluster="docker-cluster"} 0
# HELP elasticsearch_health_report_restarting_replicas The number of restarting replica shards
# TYPE elasticsearch_health_report_restarting_replicas gauge
elasticsearch_health_report_restarting_replicas{cluster="docker-cluster"} 0
# HELP elasticsearch_health_report_shards_availabilty_status Shards availabilty status
# TYPE elasticsearch_health_report_shards_availabilty_status gauge
elasticsearch_health_report_shards_availabilty_status{cluster="docker-cluster",color="green"} 1
elasticsearch_health_report_shards_availabilty_status{cluster="docker-cluster",color="red"} 0
elasticsearch_health_report_shards_availabilty_status{cluster="docker-cluster",color="yellow"} 0
# HELP elasticsearch_health_report_shards_capacity_status Shards capacity status
# TYPE elasticsearch_health_report_shards_capacity_status gauge
elasticsearch_health_report_shards_capacity_status{cluster="docker-cluster",color="green"} 1
elasticsearch_health_report_shards_capacity_status{cluster="docker-cluster",color="red"} 0
elasticsearch_health_report_shards_capacity_status{cluster="docker-cluster",color="yellow"} 0
# HELP elasticsearch_health_report_slm_policies The number of SLM policies
# TYPE elasticsearch_health_report_slm_policies gauge
elasticsearch_health_report_slm_policies{cluster="docker-cluster"} 0
# HELP elasticsearch_health_report_slm_status SLM status
# TYPE elasticsearch_health_report_slm_status gauge
elasticsearch_health_report_slm_status{cluster="docker-cluster",color="green"} 1
elasticsearch_health_report_slm_status{cluster="docker-cluster",color="red"} 0
elasticsearch_health_report_slm_status{cluster="docker-cluster",color="yellow"} 0
# HELP elasticsearch_health_report_started_primaries The number of started primary shards
# TYPE elasticsearch_health_report_started_primaries gauge
elasticsearch_health_report_started_primaries{cluster="docker-cluster"} 11703
# HELP elasticsearch_health_report_started_replicas The number of started replica shards
# TYPE elasticsearch_health_report_started_replicas gauge
elasticsearch_health_report_started_replicas{cluster="docker-cluster"} 1701
# HELP elasticsearch_health_report_status Overall cluster status
# TYPE elasticsearch_health_report_status gauge
elasticsearch_health_report_status{cluster="docker-cluster",color="green"} 1
elasticsearch_health_report_status{cluster="docker-cluster",color="red"} 0
elasticsearch_health_report_status{cluster="docker-cluster",color="yellow"} 0
# HELP elasticsearch_health_report_total_repositories The number of snapshot repositories
# TYPE elasticsearch_health_report_total_repositories gauge
elasticsearch_health_report_total_repositories{cluster="docker-cluster"} 1
# HELP elasticsearch_health_report_unassigned_primaries The number of unassigned primary shards
# TYPE elasticsearch_health_report_unassigned_primaries gauge
elasticsearch_health_report_unassigned_primaries{cluster="docker-cluster"} 0
# HELP elasticsearch_health_report_unassigned_replicas The number of unassigned replica shards
# TYPE elasticsearch_health_report_unassigned_replicas gauge
elasticsearch_health_report_unassigned_replicas{cluster="docker-cluster"} 0
`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
f, err := os.Open(tt.file)
if err != nil {
t.Fatal(err)
}
defer f.Close()
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
io.Copy(w, f)
}))
defer ts.Close()
u, err := url.Parse(ts.URL)
if err != nil {
t.Fatal(err)
}
c, err := NewHealthReport(promslog.NewNopLogger(), u, http.DefaultClient)
if err != nil {
t.Fatal(err)
}
if err := testutil.CollectAndCompare(wrapCollector{c}, strings.NewReader(tt.want)); err != nil {
t.Fatal(err)
}
})
}
}

128
collector/ilm.go Normal file
View File

@ -0,0 +1,128 @@
// Copyright 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 (
"context"
"encoding/json"
"fmt"
"log/slog"
"net/http"
"net/url"
"github.com/prometheus/client_golang/prometheus"
)
var (
ilmStatusOptions = []string{"STOPPED", "RUNNING", "STOPPING"}
ilmIndexStatus = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "ilm_index", "status"),
"Status of ILM policy for index",
[]string{"index", "phase", "action", "step"}, nil)
ilmStatus = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "ilm", "status"),
"Current status of ILM. Status can be STOPPED, RUNNING, STOPPING.",
[]string{"operation_mode"}, nil,
)
)
func init() {
registerCollector("ilm", defaultDisabled, NewILM)
}
type ILM struct {
logger *slog.Logger
hc *http.Client
u *url.URL
}
func NewILM(logger *slog.Logger, u *url.URL, hc *http.Client) (Collector, error) {
return &ILM{
logger: logger,
hc: hc,
u: u,
}, nil
}
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"`
}
type IlmStatusResponse struct {
OperationMode string `json:"operation_mode"`
}
func (i *ILM) Update(ctx context.Context, ch chan<- prometheus.Metric) error {
var ir IlmResponse
indexURL := i.u.ResolveReference(&url.URL{Path: "/_all/_ilm/explain"})
indexResp, err := getURL(ctx, i.hc, i.logger, indexURL.String())
if err != nil {
return fmt.Errorf("failed to load ILM url: %w", err)
}
if err := json.Unmarshal(indexResp, &ir); err != nil {
return fmt.Errorf("failed to decode JSON body: %w", err)
}
var isr IlmStatusResponse
indexStatusURL := i.u.ResolveReference(&url.URL{Path: "/_ilm/status"})
indexStatusResp, err := getURL(ctx, i.hc, i.logger, indexStatusURL.String())
if err != nil {
return fmt.Errorf("failed to load ILM url: %w", err)
}
if err := json.Unmarshal(indexStatusResp, &isr); err != nil {
return fmt.Errorf("failed to decode JSON body: %w", err)
}
for name, ilm := range ir.Indices {
ch <- prometheus.MustNewConstMetric(
ilmIndexStatus,
prometheus.GaugeValue,
bool2Float(ilm.Managed),
name, ilm.Phase, ilm.Action, ilm.Step,
)
}
for _, status := range ilmStatusOptions {
statusActive := false
if isr.OperationMode == status {
statusActive = true
}
ch <- prometheus.MustNewConstMetric(
ilmStatus,
prometheus.GaugeValue,
bool2Float(statusActive),
status,
)
}
return nil
}

View File

@ -1,154 +0,0 @@
// 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
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,
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
}
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 {
return ir, err
}
if err := json.Unmarshal(bts, &ir); err != nil {
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) {
// indices
ilmResp, err := i.fetchAndDecodeIlm()
if err != nil {
level.Warn(i.logger).Log(
"msg", "failed to fetch and decode ILM stats",
"err", err,
)
return
}
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,
)
}
}

View File

@ -1,111 +0,0 @@
// 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 (
"io"
"net/http"
"net/http/httptest"
"net/url"
"os"
"strings"
"testing"
"github.com/go-kit/log"
"github.com/prometheus/client_golang/prometheus/testutil"
)
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
tests := []struct {
name string
file string
want string
}{
{
name: "6.6.0",
file: "../fixtures/ilm_indices/6.6.0.json",
want: `
# HELP elasticsearch_ilm_index_status Status of ILM policy for index
# TYPE elasticsearch_ilm_index_status gauge
elasticsearch_ilm_index_status{action="",index="twitter",phase="",step=""} 0
elasticsearch_ilm_index_status{action="complete",index="facebook",phase="new",step="complete"} 1
`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
f, err := os.Open(tt.file)
if err != nil {
t.Fatal(err)
}
defer f.Close()
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
io.Copy(w, f)
}))
defer ts.Close()
u, err := url.Parse(ts.URL)
if err != nil {
t.Fatal(err)
}
c := NewIlmIndicies(log.NewNopLogger(), http.DefaultClient, u)
if err != nil {
t.Fatal(err)
}
if err := testutil.CollectAndCompare(c, strings.NewReader(tt.want)); err != nil {
t.Fatal(err)
}
})
}
}

View File

@ -1,138 +0,0 @@
// 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
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,
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
}
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 {
return nil, err
}
return &imr, nil
}
// Collect gets all indices Ilms metric values
func (im *IlmStatusCollector) Collect(ch chan<- prometheus.Metric) {
indicesIlmsResponse, err := im.fetchAndDecodeIlm()
if err != nil {
level.Warn(im.logger).Log(
"msg", "failed to fetch and decode cluster ilm status",
"err", err,
)
return
}
for _, status := range ilmStatuses {
ch <- prometheus.MustNewConstMetric(
im.metric.Desc,
im.metric.Type,
im.metric.Value(indicesIlmsResponse, status),
status,
)
}
}

94
collector/ilm_test.go Normal file
View File

@ -0,0 +1,94 @@
// Copyright 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 (
"io"
"net/http"
"net/http/httptest"
"net/url"
"os"
"path"
"strings"
"testing"
"github.com/prometheus/client_golang/prometheus/testutil"
"github.com/prometheus/common/promslog"
)
func TestILM(t *testing.T) {
tests := []struct {
name string
file string
want string
}{
{
name: "6.6.0",
file: "6.6.0.json",
want: `
# HELP elasticsearch_ilm_index_status Status of ILM policy for index
# TYPE elasticsearch_ilm_index_status gauge
elasticsearch_ilm_index_status{action="",index="twitter",phase="",step=""} 0
elasticsearch_ilm_index_status{action="complete",index="facebook",phase="new",step="complete"} 1
# HELP elasticsearch_ilm_status Current status of ILM. Status can be STOPPED, RUNNING, STOPPING.
# TYPE elasticsearch_ilm_status gauge
elasticsearch_ilm_status{operation_mode="RUNNING"} 1
elasticsearch_ilm_status{operation_mode="STOPPED"} 0
elasticsearch_ilm_status{operation_mode="STOPPING"} 0
`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
indexF, err := os.Open(path.Join("../fixtures/ilm_indices", tt.file))
if err != nil {
t.Fatal(err)
}
defer indexF.Close()
statusF, err := os.Open(path.Join("../fixtures/ilm_status", tt.file))
if err != nil {
t.Fatal(err)
}
defer statusF.Close()
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
sm := http.NewServeMux()
sm.HandleFunc("/_all/_ilm/explain", func(w http.ResponseWriter, r *http.Request) {
io.Copy(w, indexF)
})
sm.HandleFunc("/_ilm/status", func(w http.ResponseWriter, r *http.Request) {
io.Copy(w, statusF)
})
sm.ServeHTTP(w, r)
}))
defer ts.Close()
u, err := url.Parse(ts.URL)
if err != nil {
t.Fatal(err)
}
c, err := NewILM(promslog.NewNopLogger(), u, http.DefaultClient)
if err != nil {
t.Fatal(err)
}
if err := testutil.CollectAndCompare(wrapCollector{c}, strings.NewReader(tt.want)); err != nil {
t.Fatal(err)
}
})
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
// Copyright 2021 The Prometheus Authors
// Copyright 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
@ -17,18 +17,15 @@ import (
"encoding/json"
"fmt"
"io"
"log/slog"
"net/http"
"net/url"
"path"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/prometheus/client_golang/prometheus"
)
var (
defaultIndicesMappingsLabels = []string{"index"}
)
var defaultIndicesMappingsLabels = []string{"index"}
type indicesMappingsMetric struct {
Type prometheus.ValueType
@ -38,7 +35,7 @@ type indicesMappingsMetric struct {
// IndicesMappings information struct
type IndicesMappings struct {
logger log.Logger
logger *slog.Logger
client *http.Client
url *url.URL
@ -46,7 +43,7 @@ type IndicesMappings struct {
}
// NewIndicesMappings defines Indices IndexMappings Prometheus metrics
func NewIndicesMappings(logger log.Logger, client *http.Client, url *url.URL) *IndicesMappings {
func NewIndicesMappings(logger *slog.Logger, client *http.Client, url *url.URL) *IndicesMappings {
subsystem := "indices_mappings_stats"
return &IndicesMappings{
@ -73,7 +70,6 @@ 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.Type != "object" {
// property has a type set - counts as a field unless the value is object
// as the recursion below will handle counting that
@ -117,13 +113,13 @@ func (im *IndicesMappings) getAndParseURL(u *url.URL) (*IndicesMappingsResponse,
body, err := io.ReadAll(res.Body)
if err != nil {
level.Warn(im.logger).Log("msg", "failed to read response body", "err", err)
im.logger.Warn("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)
im.logger.Warn("failed to close response body", "err", err)
return nil, err
}
@ -145,8 +141,8 @@ func (im *IndicesMappings) fetchAndDecodeIndicesMappings() (*IndicesMappingsResp
func (im *IndicesMappings) Collect(ch chan<- prometheus.Metric) {
indicesMappingsResponse, err := im.fetchAndDecodeIndicesMappings()
if err != nil {
level.Warn(im.logger).Log(
"msg", "failed to fetch and decode cluster mappings stats",
im.logger.Warn(
"failed to fetch and decode cluster mappings stats",
"err", err,
)
return

View File

@ -1,4 +1,4 @@
// Copyright 2021 The Prometheus Authors
// Copyright 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

View File

@ -1,4 +1,4 @@
// Copyright 2021 The Prometheus Authors
// Copyright 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
@ -22,8 +22,8 @@ import (
"strings"
"testing"
"github.com/go-kit/log"
"github.com/prometheus/client_golang/prometheus/testutil"
"github.com/prometheus/common/promslog"
)
func TestMapping(t *testing.T) {
@ -113,7 +113,7 @@ elasticsearch_indices_mappings_stats_fields{index="test-data-2023.01.20"} 40
t.Fatal(err)
}
c := NewIndicesMappings(log.NewNopLogger(), http.DefaultClient, u)
c := NewIndicesMappings(promslog.NewNopLogger(), http.DefaultClient, u)
if err != nil {
t.Fatal(err)
}

View File

@ -1,4 +1,4 @@
// Copyright 2021 The Prometheus Authors
// Copyright 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
@ -89,16 +89,17 @@ type IndexStatsIndexStoreResponse struct {
// IndexStatsIndexIndexingResponse defines index stats index indexing information structure
type IndexStatsIndexIndexingResponse struct {
IndexTotal int64 `json:"index_total"`
IndexTimeInMillis int64 `json:"index_time_in_millis"`
IndexCurrent int64 `json:"index_current"`
IndexFailed int64 `json:"index_failed"`
DeleteTotal int64 `json:"delete_total"`
DeleteTimeInMillis int64 `json:"delete_time_in_millis"`
DeleteCurrent int64 `json:"delete_current"`
NoopUpdateTotal int64 `json:"noop_update_total"`
IsThrottled bool `json:"is_throttled"`
ThrottleTimeInMillis int64 `json:"throttle_time_in_millis"`
IndexTotal int64 `json:"index_total"`
IndexTimeInMillis int64 `json:"index_time_in_millis"`
IndexCurrent int64 `json:"index_current"`
IndexFailed *int64 `json:"index_failed,omitempty"`
DeleteTotal int64 `json:"delete_total"`
DeleteTimeInMillis int64 `json:"delete_time_in_millis"`
DeleteCurrent int64 `json:"delete_current"`
NoopUpdateTotal int64 `json:"noop_update_total"`
IsThrottled bool `json:"is_throttled"`
ThrottleTimeInMillis int64 `json:"throttle_time_in_millis"`
WriteLoad *float64 `json:"write_load,omitempty"`
}
// IndexStatsIndexGetResponse defines index stats index get information structure
@ -145,9 +146,11 @@ type IndexStatsIndexMergesResponse struct {
// IndexStatsIndexRefreshResponse defines index stats index refresh information structure
type IndexStatsIndexRefreshResponse struct {
Total int64 `json:"total"`
TotalTimeInMillis int64 `json:"total_time_in_millis"`
Listeners int64 `json:"listeners"`
Total int64 `json:"total"`
TotalTimeInMillis int64 `json:"total_time_in_millis"`
ExternalTotal int64 `json:"external_total"`
ExternalTotalTimeInMillis int64 `json:"external_total_time_in_millis"`
Listeners int64 `json:"listeners"`
}
// IndexStatsIndexFlushResponse defines index stats index flush information structure

View File

@ -1,4 +1,4 @@
// Copyright 2021 The Prometheus Authors
// Copyright 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
@ -17,33 +17,30 @@ import (
"encoding/json"
"fmt"
"io"
"log/slog"
"net/http"
"net/url"
"path"
"strconv"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/prometheus/client_golang/prometheus"
)
// IndicesSettings information struct
type IndicesSettings struct {
logger log.Logger
logger *slog.Logger
client *http.Client
url *url.URL
up prometheus.Gauge
readOnlyIndices prometheus.Gauge
totalScrapes, jsonParseFailures prometheus.Counter
metrics []*indicesSettingsMetric
metrics []*indicesSettingsMetric
}
var (
defaultIndicesTotalFieldsLabels = []string{"index"}
defaultTotalFieldsValue = 1000 //es default configuration for total fields
defaultDateCreation = 0 //es index default creation date
defaultTotalFieldsValue = 1000 // es default configuration for total fields
defaultDateCreation = 0 // es index default creation date
)
type indicesSettingsMetric struct {
@ -53,28 +50,17 @@ type indicesSettingsMetric struct {
}
// NewIndicesSettings defines Indices Settings Prometheus metrics
func NewIndicesSettings(logger log.Logger, client *http.Client, url *url.URL) *IndicesSettings {
func NewIndicesSettings(logger *slog.Logger, client *http.Client, url *url.URL) *IndicesSettings {
return &IndicesSettings{
logger: logger,
client: client,
url: url,
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.",
}),
totalScrapes: prometheus.NewCounter(prometheus.CounterOpts{
Name: prometheus.BuildFQName(namespace, "indices_settings_stats", "total_scrapes"),
Help: "Current total Elasticsearch Indices Settings scrapes.",
}),
readOnlyIndices: prometheus.NewGauge(prometheus.GaugeOpts{
Name: prometheus.BuildFQName(namespace, "indices_settings_stats", "read_only_indices"),
Help: "Current number of read only indices within cluster",
}),
jsonParseFailures: prometheus.NewCounter(prometheus.CounterOpts{
Name: prometheus.BuildFQName(namespace, "indices_settings_stats", "json_parse_failures"),
Help: "Number of errors while parsing JSON.",
}),
metrics: []*indicesSettingsMetric{
{
Type: prometheus.GaugeValue,
@ -127,10 +113,11 @@ func NewIndicesSettings(logger log.Logger, client *http.Client, url *url.URL) *I
// Describe add Snapshots metrics descriptions
func (cs *IndicesSettings) Describe(ch chan<- *prometheus.Desc) {
ch <- cs.up.Desc()
ch <- cs.totalScrapes.Desc()
ch <- cs.readOnlyIndices.Desc()
ch <- cs.jsonParseFailures.Desc()
for _, metric := range cs.metrics {
ch <- metric.Desc
}
}
func (cs *IndicesSettings) getAndParseURL(u *url.URL, data interface{}) error {
@ -143,8 +130,8 @@ func (cs *IndicesSettings) getAndParseURL(u *url.URL, data interface{}) error {
defer func() {
err = res.Body.Close()
if err != nil {
level.Warn(cs.logger).Log(
"msg", "failed to close http.Client",
cs.logger.Warn(
"failed to close http.Client",
"err", err,
)
}
@ -156,19 +143,16 @@ func (cs *IndicesSettings) getAndParseURL(u *url.URL, data interface{}) error {
bts, err := io.ReadAll(res.Body)
if err != nil {
cs.jsonParseFailures.Inc()
return err
}
if err := json.Unmarshal(bts, data); err != nil {
cs.jsonParseFailures.Inc()
return err
}
return nil
}
func (cs *IndicesSettings) fetchAndDecodeIndicesSettings() (IndicesSettingsResponse, error) {
u := *cs.url
u.Path = path.Join(u.Path, "/_all/_settings")
var asr IndicesSettingsResponse
@ -182,26 +166,15 @@ func (cs *IndicesSettings) fetchAndDecodeIndicesSettings() (IndicesSettingsRespo
// Collect gets all indices settings metric values
func (cs *IndicesSettings) Collect(ch chan<- prometheus.Metric) {
cs.totalScrapes.Inc()
defer func() {
ch <- cs.up
ch <- cs.totalScrapes
ch <- cs.jsonParseFailures
ch <- cs.readOnlyIndices
}()
asr, err := cs.fetchAndDecodeIndicesSettings()
if err != nil {
cs.readOnlyIndices.Set(0)
cs.up.Set(0)
level.Warn(cs.logger).Log(
"msg", "failed to fetch and decode cluster settings stats",
cs.logger.Warn(
"failed to fetch and decode cluster settings stats",
"err", err,
)
return
}
cs.up.Set(1)
var c int
for indexName, value := range asr {
@ -218,4 +191,6 @@ func (cs *IndicesSettings) Collect(ch chan<- prometheus.Metric) {
}
}
cs.readOnlyIndices.Set(float64(c))
ch <- cs.readOnlyIndices
}

View File

@ -1,4 +1,4 @@
// Copyright 2021 The Prometheus Authors
// Copyright 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

View File

@ -1,4 +1,4 @@
// Copyright 2021 The Prometheus Authors
// Copyright 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
@ -14,13 +14,17 @@
package collector
import (
"fmt"
"io"
"net/http"
"net/http/httptest"
"net/url"
"os"
"path"
"strings"
"testing"
"github.com/go-kit/log"
"github.com/prometheus/client_golang/prometheus/testutil"
"github.com/prometheus/common/promslog"
)
func TestIndicesSettings(t *testing.T) {
@ -54,53 +58,65 @@ func TestIndicesSettings(t *testing.T) {
// curl http://localhost:9200/_all/_settings
tcs := map[string]string{
"6.5.4": `{"viber":{"settings":{"index":{"creation_date":"1618593207186","number_of_shards":"5","number_of_replicas":"1","uuid":"lWg86KTARzO3r7lELytT1Q","version":{"created":"6050499"},"provided_name":"viber"}}},"instagram":{"settings":{"index":{"mapping":{"total_fields":{"limit":"10000"}},"number_of_shards":"5","blocks":{"read_only_allow_delete":"true"},"provided_name":"instagram","creation_date":"1618593203353","number_of_replicas":"1","uuid":"msb6eG7aT8GmNe-a4oyVtQ","version":{"created":"6050499"}}}},"twitter":{"settings":{"index":{"number_of_shards":"5","blocks":{"read_only_allow_delete":"true"},"provided_name":"twitter","creation_date":"1618593193641","number_of_replicas":"1","uuid":"YRUT8t4aSkKsNmGl7K3y4Q","version":{"created":"6050499"}}}},"facebook":{"settings":{"index":{"creation_date":"1618593199101","number_of_shards":"5","number_of_replicas":"1","uuid":"trZhb_YOTV-RWKitTYw81A","version":{"created":"6050499"},"provided_name":"facebook"}}}}`,
tests := []struct {
name string
file string
want string
}{
{
name: "6.5.4",
file: "6.5.4.json",
want: `# HELP elasticsearch_indices_settings_creation_timestamp_seconds index setting creation_date
# TYPE elasticsearch_indices_settings_creation_timestamp_seconds gauge
elasticsearch_indices_settings_creation_timestamp_seconds{index="facebook"} 1.618593199101e+09
elasticsearch_indices_settings_creation_timestamp_seconds{index="instagram"} 1.618593203353e+09
elasticsearch_indices_settings_creation_timestamp_seconds{index="twitter"} 1.618593193641e+09
elasticsearch_indices_settings_creation_timestamp_seconds{index="viber"} 1.618593207186e+09
# HELP elasticsearch_indices_settings_replicas index setting number_of_replicas
# TYPE elasticsearch_indices_settings_replicas gauge
elasticsearch_indices_settings_replicas{index="facebook"} 1
elasticsearch_indices_settings_replicas{index="instagram"} 1
elasticsearch_indices_settings_replicas{index="twitter"} 1
elasticsearch_indices_settings_replicas{index="viber"} 1
# HELP elasticsearch_indices_settings_stats_read_only_indices Current number of read only indices within cluster
# TYPE elasticsearch_indices_settings_stats_read_only_indices gauge
elasticsearch_indices_settings_stats_read_only_indices 2
# HELP elasticsearch_indices_settings_total_fields index mapping setting for total_fields
# TYPE elasticsearch_indices_settings_total_fields gauge
elasticsearch_indices_settings_total_fields{index="facebook"} 1000
elasticsearch_indices_settings_total_fields{index="instagram"} 10000
elasticsearch_indices_settings_total_fields{index="twitter"} 1000
elasticsearch_indices_settings_total_fields{index="viber"} 1000
`,
},
}
for ver, out := range tcs {
for hn, handler := range map[string]http.Handler{
"plain": http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, out)
}),
} {
ts := httptest.NewServer(handler)
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
f, err := os.Open(path.Join("../fixtures/indices_settings", tt.file))
if err != nil {
t.Fatal(err)
}
defer f.Close()
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
io.Copy(w, f)
}))
defer ts.Close()
u, err := url.Parse(ts.URL)
if err != nil {
t.Fatalf("Failed to parse URL: %s", err)
t.Fatal(err)
}
c := NewIndicesSettings(log.NewNopLogger(), http.DefaultClient, u)
nsr, err := c.fetchAndDecodeIndicesSettings()
c := NewIndicesSettings(promslog.NewNopLogger(), http.DefaultClient, u)
if err != nil {
t.Fatalf("Failed to fetch or decode indices settings: %s", err)
t.Fatal(err)
}
t.Logf("[%s/%s] All Indices Settings Response: %+v", hn, ver, nsr)
// if nsr.Cluster.Routing.Allocation.Enabled != "ALL" {
// t.Errorf("Wrong setting for cluster routing allocation enabled")
// }
var counter int
var totalFields int
for key, value := range nsr {
if value.Settings.IndexInfo.Blocks.ReadOnly == "true" {
counter++
if key != "instagram" && key != "twitter" {
t.Errorf("Wrong read_only index")
}
}
if value.Settings.IndexInfo.Mapping.TotalFields.Limit == "10000" {
totalFields++
if key != "instagram" {
t.Errorf("Expected 10000 total_fields only for instagram")
}
}
if err := testutil.CollectAndCompare(c, strings.NewReader(tt.want)); err != nil {
t.Fatal(err)
}
if counter != 2 {
t.Errorf("Wrong number of read_only indexes")
}
if totalFields != 1 {
t.Errorf(("Wrong number of total_fields found"))
}
}
})
}
}

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
// Copyright 2021 The Prometheus Authors
// Copyright 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
@ -17,12 +17,11 @@ import (
"encoding/json"
"fmt"
"io"
"log/slog"
"net/http"
"net/url"
"path"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/prometheus/client_golang/prometheus"
)
@ -70,32 +69,18 @@ func getRoles(node NodeStatsNodeResponse) map[string]bool {
return roles
}
func createRoleMetric(role string) *nodeMetric {
return &nodeMetric{
Type: prometheus.GaugeValue,
Desc: prometheus.NewDesc(
prometheus.BuildFQName(namespace, "nodes", "roles"),
"Node roles",
defaultRoleLabels, prometheus.Labels{"role": role},
),
Value: func(node NodeStatsNodeResponse) float64 {
return 1.0
},
Labels: func(cluster string, node NodeStatsNodeResponse) []string {
return []string{
cluster,
node.Host,
node.Name,
}
},
}
}
var nodesRolesMetric = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "nodes", "roles"),
"Node roles",
append(defaultRoleLabels, "role"), nil,
)
var (
defaultNodeLabels = []string{"cluster", "host", "name", "es_master_node", "es_data_node", "es_ingest_node", "es_client_node"}
defaultRoleLabels = []string{"cluster", "host", "name"}
defaultRoleLabels = []string{"cluster", "host", "name", "node"}
defaultThreadPoolLabels = append(defaultNodeLabels, "type")
defaultBreakerLabels = append(defaultNodeLabels, "breaker")
defaultIndexingPressureLabels = []string{"cluster", "host", "name", "indexing_pressure"}
defaultFilesystemDataLabels = append(defaultNodeLabels, "mount", "path")
defaultFilesystemIODeviceLabels = append(defaultNodeLabels, "device")
defaultCacheLabels = append(defaultNodeLabels, "cache")
@ -150,6 +135,13 @@ type breakerMetric struct {
Labels func(cluster string, node NodeStatsNodeResponse, breaker string) []string
}
type indexingPressureMetric struct {
Type prometheus.ValueType
Desc *prometheus.Desc
Value func(indexingPressureStats NodeStatsIndexingPressureResponse) float64
Labels func(cluster string, node NodeStatsNodeResponse, indexingPressure string) []string
}
type threadPoolMetric struct {
Type prometheus.ValueType
Desc *prometheus.Desc
@ -173,25 +165,23 @@ type filesystemIODeviceMetric struct {
// Nodes information struct
type Nodes struct {
logger log.Logger
logger *slog.Logger
client *http.Client
url *url.URL
all bool
node string
up prometheus.Gauge
totalScrapes, jsonParseFailures prometheus.Counter
nodeMetrics []*nodeMetric
gcCollectionMetrics []*gcCollectionMetric
breakerMetrics []*breakerMetric
indexingPressureMetrics []*indexingPressureMetric
threadPoolMetrics []*threadPoolMetric
filesystemDataMetrics []*filesystemDataMetric
filesystemIODeviceMetrics []*filesystemIODeviceMetric
}
// NewNodes defines Nodes Prometheus metrics
func NewNodes(logger log.Logger, client *http.Client, url *url.URL, all bool, node string) *Nodes {
func NewNodes(logger *slog.Logger, client *http.Client, url *url.URL, all bool, node string) *Nodes {
return &Nodes{
logger: logger,
client: client,
@ -199,19 +189,6 @@ func NewNodes(logger log.Logger, client *http.Client, url *url.URL, all bool, no
all: all,
node: node,
up: prometheus.NewGauge(prometheus.GaugeOpts{
Name: prometheus.BuildFQName(namespace, "node_stats", "up"),
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.",
}),
jsonParseFailures: prometheus.NewCounter(prometheus.CounterOpts{
Name: prometheus.BuildFQName(namespace, "node_stats", "json_parse_failures"),
Help: "Number of errors while parsing JSON.",
}),
nodeMetrics: []*nodeMetric{
{
Type: prometheus.GaugeValue,
@ -621,6 +598,30 @@ func NewNodes(logger log.Logger, client *http.Client, url *url.URL, all bool, no
},
Labels: defaultNodeLabelValues,
},
{
Type: prometheus.CounterValue,
Desc: prometheus.NewDesc(
prometheus.BuildFQName(namespace, "indices_refresh", "external_total"),
"Total external refreshes",
defaultNodeLabels, nil,
),
Value: func(node NodeStatsNodeResponse) float64 {
return float64(node.Indices.Refresh.ExternalTotal)
},
Labels: defaultNodeLabelValues,
},
{
Type: prometheus.CounterValue,
Desc: prometheus.NewDesc(
prometheus.BuildFQName(namespace, "indices_refresh", "external_time_seconds_total"),
"Total time spent external refreshing in seconds",
defaultNodeLabels, nil,
),
Value: func(node NodeStatsNodeResponse) float64 {
return float64(node.Indices.Refresh.ExternalTotalTimeInMillis) / 1000
},
Labels: defaultNodeLabelValues,
},
{
Type: prometheus.CounterValue,
Desc: prometheus.NewDesc(
@ -1607,6 +1608,46 @@ func NewNodes(logger log.Logger, client *http.Client, url *url.URL, all bool, no
},
},
},
indexingPressureMetrics: []*indexingPressureMetric{
{
Type: prometheus.GaugeValue,
Desc: prometheus.NewDesc(
prometheus.BuildFQName(namespace, "indexing_pressure", "current_all_in_bytes"),
"Memory consumed, in bytes, by indexing requests in the coordinating, primary, or replica stage.",
defaultIndexingPressureLabels, nil,
),
Value: func(indexingPressureMem NodeStatsIndexingPressureResponse) float64 {
return float64(indexingPressureMem.Current.AllInBytes)
},
Labels: func(cluster string, node NodeStatsNodeResponse, indexingPressure string) []string {
return []string{
cluster,
node.Host,
node.Name,
indexingPressure,
}
},
},
{
Type: prometheus.GaugeValue,
Desc: prometheus.NewDesc(
prometheus.BuildFQName(namespace, "indexing_pressure", "limit_in_bytes"),
"Configured memory limit, in bytes, for the indexing requests",
defaultIndexingPressureLabels, nil,
),
Value: func(indexingPressureStats NodeStatsIndexingPressureResponse) float64 {
return float64(indexingPressureStats.LimitInBytes)
},
Labels: func(cluster string, node NodeStatsNodeResponse, indexingPressure string) []string {
return []string{
cluster,
node.Host,
node.Name,
indexingPressure,
}
},
},
},
threadPoolMetrics: []*threadPoolMetric{
{
Type: prometheus.CounterValue,
@ -1786,12 +1827,20 @@ func NewNodes(logger log.Logger, client *http.Client, url *url.URL, all bool, no
// Describe add metrics descriptions
func (c *Nodes) Describe(ch chan<- *prometheus.Desc) {
ch <- nodesRolesMetric
for _, metric := range c.nodeMetrics {
ch <- metric.Desc
}
for _, metric := range c.gcCollectionMetrics {
ch <- metric.Desc
}
for _, metric := range c.breakerMetrics {
ch <- metric.Desc
}
for _, metric := range c.indexingPressureMetrics {
ch <- metric.Desc
}
for _, metric := range c.threadPoolMetrics {
ch <- metric.Desc
}
@ -1801,9 +1850,6 @@ func (c *Nodes) Describe(ch chan<- *prometheus.Desc) {
for _, metric := range c.filesystemIODeviceMetrics {
ch <- metric.Desc
}
ch <- c.up.Desc()
ch <- c.totalScrapes.Desc()
ch <- c.jsonParseFailures.Desc()
}
func (c *Nodes) fetchAndDecodeNodeStats() (nodeStatsResponse, error) {
@ -1826,8 +1872,8 @@ func (c *Nodes) fetchAndDecodeNodeStats() (nodeStatsResponse, error) {
defer func() {
err = res.Body.Close()
if err != nil {
level.Warn(c.logger).Log(
"msg", "failed to close http.Client",
c.logger.Warn(
"failed to close http.Client",
"err", err,
)
}
@ -1839,12 +1885,10 @@ func (c *Nodes) fetchAndDecodeNodeStats() (nodeStatsResponse, error) {
bts, err := io.ReadAll(res.Body)
if err != nil {
c.jsonParseFailures.Inc()
return nsr, err
}
if err := json.Unmarshal(bts, &nsr); err != nil {
c.jsonParseFailures.Inc()
return nsr, err
}
return nsr, nil
@ -1852,38 +1896,39 @@ func (c *Nodes) fetchAndDecodeNodeStats() (nodeStatsResponse, error) {
// Collect gets nodes metric values
func (c *Nodes) Collect(ch chan<- prometheus.Metric) {
c.totalScrapes.Inc()
defer func() {
ch <- c.up
ch <- c.totalScrapes
ch <- c.jsonParseFailures
}()
nodeStatsResp, err := c.fetchAndDecodeNodeStats()
if err != nil {
c.up.Set(0)
level.Warn(c.logger).Log(
"msg", "failed to fetch and decode node stats",
c.logger.Warn(
"failed to fetch and decode node stats",
"err", err,
)
return
}
c.up.Set(1)
for _, node := range nodeStatsResp.Nodes {
for nodeID, node := range nodeStatsResp.Nodes {
// Handle the node labels metric
roles := getRoles(node)
for role, roleEnabled := range roles {
val := 0.0
if roleEnabled {
metric := createRoleMetric(role)
ch <- prometheus.MustNewConstMetric(
metric.Desc,
metric.Type,
metric.Value(node),
metric.Labels(nodeStatsResp.ClusterName, node)...,
)
val = 1.0
}
labels := []string{
nodeStatsResp.ClusterName,
node.Host,
node.Name,
nodeID,
role,
}
ch <- prometheus.MustNewConstMetric(
nodesRolesMetric,
prometheus.GaugeValue,
val,
labels...,
)
}
for _, metric := range c.nodeMetrics {
@ -1919,6 +1964,18 @@ func (c *Nodes) Collect(ch chan<- prometheus.Metric) {
}
}
// Indexing Pressure stats
for indexingPressure, ipstats := range node.IndexingPressure {
for _, metric := range c.indexingPressureMetrics {
ch <- prometheus.MustNewConstMetric(
metric.Desc,
metric.Type,
metric.Value(ipstats),
metric.Labels(nodeStatsResp.ClusterName, node, indexingPressure)...,
)
}
}
// Thread Pool stats
for pool, pstats := range node.ThreadPool {
for _, metric := range c.threadPoolMetrics {
@ -1954,6 +2011,5 @@ func (c *Nodes) Collect(ch chan<- prometheus.Metric) {
)
}
}
}
}

View File

@ -1,4 +1,4 @@
// Copyright 2021 The Prometheus Authors
// Copyright 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
@ -23,23 +23,24 @@ type nodeStatsResponse struct {
// NodeStatsNodeResponse defines node stats information structure for nodes
type NodeStatsNodeResponse struct {
Name string `json:"name"`
Host string `json:"host"`
Timestamp int64 `json:"timestamp"`
TransportAddress string `json:"transport_address"`
Hostname string `json:"hostname"`
Roles []string `json:"roles"`
Attributes map[string]string `json:"attributes"`
Indices NodeStatsIndicesResponse `json:"indices"`
OS NodeStatsOSResponse `json:"os"`
Network NodeStatsNetworkResponse `json:"network"`
FS NodeStatsFSResponse `json:"fs"`
ThreadPool map[string]NodeStatsThreadPoolPoolResponse `json:"thread_pool"`
JVM NodeStatsJVMResponse `json:"jvm"`
Breakers map[string]NodeStatsBreakersResponse `json:"breakers"`
HTTP map[string]interface{} `json:"http"`
Transport NodeStatsTransportResponse `json:"transport"`
Process NodeStatsProcessResponse `json:"process"`
Name string `json:"name"`
Host string `json:"host"`
Timestamp int64 `json:"timestamp"`
TransportAddress string `json:"transport_address"`
Hostname string `json:"hostname"`
Roles []string `json:"roles"`
Attributes map[string]string `json:"attributes"`
Indices NodeStatsIndicesResponse `json:"indices"`
OS NodeStatsOSResponse `json:"os"`
Network NodeStatsNetworkResponse `json:"network"`
FS NodeStatsFSResponse `json:"fs"`
ThreadPool map[string]NodeStatsThreadPoolPoolResponse `json:"thread_pool"`
JVM NodeStatsJVMResponse `json:"jvm"`
Breakers map[string]NodeStatsBreakersResponse `json:"breakers"`
HTTP map[string]interface{} `json:"http"`
Transport NodeStatsTransportResponse `json:"transport"`
Process NodeStatsProcessResponse `json:"process"`
IndexingPressure map[string]NodeStatsIndexingPressureResponse `json:"indexing_pressure"`
}
// NodeStatsBreakersResponse is a representation of a statistics about the field data circuit breaker
@ -50,6 +51,17 @@ type NodeStatsBreakersResponse struct {
Tripped int64 `json:"tripped"`
}
// NodeStatsIndexingPressureResponse is a representation of a elasticsearch indexing pressure
type NodeStatsIndexingPressureResponse struct {
Current NodeStatsIndexingPressureCurrentResponse `json:"current"`
LimitInBytes int64 `json:"limit_in_bytes"`
}
// NodeStatsIndexingPressureMemoryCurrentResponse is a representation of a elasticsearch indexing pressure current memory usage
type NodeStatsIndexingPressureCurrentResponse struct {
AllInBytes int64 `json:"all_in_bytes"`
}
// NodeStatsJVMResponse is a representation of a JVM stats, memory pool information, garbage collection, buffer pools, number of loaded/unloaded classes
type NodeStatsJVMResponse struct {
BufferPools map[string]NodeStatsJVMBufferPoolResponse `json:"buffer_pools"`
@ -160,8 +172,10 @@ type NodeStatsIndicesDocsResponse struct {
// NodeStatsIndicesRefreshResponse defines node stats refresh information structure for indices
type NodeStatsIndicesRefreshResponse struct {
Total int64 `json:"total"`
TotalTime int64 `json:"total_time_in_millis"`
Total int64 `json:"total"`
TotalTime int64 `json:"total_time_in_millis"`
ExternalTotal int64 `json:"external_total"`
ExternalTotalTimeInMillis int64 `json:"external_total_time_in_millis"`
}
// NodeStatsIndicesTranslogResponse defines node stats translog information structure for indices

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
// Copyright 2022 The Prometheus Authors
// Copyright 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
@ -16,14 +16,14 @@ package collector
import (
"encoding/json"
"fmt"
"github.com/prometheus-community/elasticsearch_exporter/pkg/clusterinfo"
"log/slog"
"net/http"
"net/url"
"path"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus-community/elasticsearch_exporter/pkg/clusterinfo"
)
// ShardResponse has shard's node and index info
@ -36,7 +36,7 @@ type ShardResponse struct {
// Shards information struct
type Shards struct {
logger log.Logger
logger *slog.Logger
client *http.Client
url *url.URL
clusterInfoCh chan *clusterinfo.Response
@ -64,24 +64,50 @@ type nodeShardMetric struct {
Labels labels
}
// NewShards defines Shards Prometheus metrics
func NewShards(logger log.Logger, client *http.Client, url *url.URL) *Shards {
// fetchClusterNameOnce performs a single request to the root endpoint to obtain the cluster name.
func fetchClusterNameOnce(s *Shards) string {
if s.lastClusterInfo != nil && s.lastClusterInfo.ClusterName != "unknown_cluster" {
return s.lastClusterInfo.ClusterName
}
u := *s.url
u.Path = path.Join(u.Path, "/")
resp, err := s.client.Get(u.String())
if err == nil {
defer resp.Body.Close()
if resp.StatusCode == http.StatusOK {
var root struct {
ClusterName string `json:"cluster_name"`
}
if err := json.NewDecoder(resp.Body).Decode(&root); err == nil && root.ClusterName != "" {
s.lastClusterInfo = &clusterinfo.Response{ClusterName: root.ClusterName}
return root.ClusterName
}
}
}
return "unknown_cluster"
}
// NewShards defines Shards Prometheus metrics
func NewShards(logger *slog.Logger, client *http.Client, url *url.URL) *Shards {
var shardPtr *Shards
nodeLabels := labels{
keys: func(...string) []string {
return []string{"node", "cluster"}
},
values: func(lastClusterinfo *clusterinfo.Response, s ...string) []string {
values: func(lastClusterinfo *clusterinfo.Response, base ...string) []string {
if lastClusterinfo != nil {
return append(s, lastClusterinfo.ClusterName)
return append(base, 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")
if shardPtr != nil {
return append(base, fetchClusterNameOnce(shardPtr))
}
return append(base, "unknown_cluster")
},
}
shards := &Shards{
// will assign later
logger: logger,
client: client,
url: url,
@ -103,7 +129,8 @@ func NewShards(logger log.Logger, client *http.Client, url *url.URL) *Shards {
return shards
},
Labels: nodeLabels,
}},
},
},
jsonParseFailures: prometheus.NewCounter(prometheus.CounterOpts{
Name: prometheus.BuildFQName(namespace, "node_shards", "json_parse_failures"),
@ -113,16 +140,17 @@ func NewShards(logger log.Logger, client *http.Client, url *url.URL) *Shards {
// start go routine to fetch clusterinfo updates and save them to lastClusterinfo
go func() {
level.Debug(logger).Log("msg", "starting cluster info receive loop")
logger.Debug("starting cluster info receive loop")
for ci := range shards.clusterInfoCh {
if ci != nil {
level.Debug(logger).Log("msg", "received cluster info update", "cluster", ci.ClusterName)
logger.Debug("received cluster info update", "cluster", ci.ClusterName)
shards.lastClusterInfo = ci
}
}
level.Debug(logger).Log("msg", "exiting cluster info receive loop")
logger.Debug("exiting cluster info receive loop")
}()
shardPtr = shards
return shards
}
@ -145,8 +173,8 @@ func (s *Shards) getAndParseURL(u *url.URL) ([]ShardResponse, error) {
defer func() {
err = res.Body.Close()
if err != nil {
level.Warn(s.logger).Log(
"msg", "failed to close http.Client",
s.logger.Warn(
"failed to close http.Client",
"err", err,
)
}
@ -164,7 +192,6 @@ func (s *Shards) getAndParseURL(u *url.URL) ([]ShardResponse, error) {
}
func (s *Shards) fetchAndDecodeShards() ([]ShardResponse, error) {
u := *s.url
u.Path = path.Join(u.Path, "/_cat/shards")
q := u.Query()
@ -179,15 +206,14 @@ func (s *Shards) fetchAndDecodeShards() ([]ShardResponse, error) {
// Collect number of shards on each node
func (s *Shards) Collect(ch chan<- prometheus.Metric) {
defer func() {
ch <- s.jsonParseFailures
}()
sr, err := s.fetchAndDecodeShards()
if err != nil {
level.Warn(s.logger).Log(
"msg", "failed to fetch and decode node shards stats",
s.logger.Warn(
"failed to fetch and decode node shards stats",
"err", err,
)
return

View File

@ -1,4 +1,4 @@
// Copyright 2023 The Prometheus Authors
// Copyright 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
@ -19,38 +19,42 @@ import (
"net/http/httptest"
"net/url"
"os"
"path"
"strings"
"testing"
"github.com/go-kit/log"
"github.com/prometheus/client_golang/prometheus/testutil"
"github.com/prometheus/common/promslog"
)
func TestILMStatus(t *testing.T) {
func TestShards(t *testing.T) {
// Testcases created using:
// docker run -d -p 9200:9200 elasticsearch:VERSION
// curl http://localhost:9200/_ilm/status
// docker run --rm -d -p 9200:9200 -e "discovery.type=single-node" docker.elastic.co/elasticsearch/elasticsearch:$VERSION
// curl -XPUT http://localhost:9200/testindex
// curl -XPUT http://localhost:9200/otherindex
// curl http://localhost:9200/_cat/shards?format=json > fixtures/shards/$VERSION.json
tests := []struct {
name string
file string
want string
}{
{
name: "6.6.0",
file: "../fixtures/ilm_status/6.6.0.json",
want: `
# HELP elasticsearch_ilm_status Current status of ilm. Status can be STOPPED, RUNNING, STOPPING.
# TYPE elasticsearch_ilm_status gauge
elasticsearch_ilm_status{operation_mode="RUNNING"} 1
elasticsearch_ilm_status{operation_mode="STOPPED"} 0
elasticsearch_ilm_status{operation_mode="STOPPING"} 0
`,
name: "7.15.0",
file: "7.15.0.json",
want: `# HELP elasticsearch_node_shards_json_parse_failures Number of errors while parsing JSON.
# TYPE elasticsearch_node_shards_json_parse_failures counter
elasticsearch_node_shards_json_parse_failures 0
# HELP elasticsearch_node_shards_total Total shards per node
# TYPE elasticsearch_node_shards_total gauge
elasticsearch_node_shards_total{cluster="unknown_cluster",node="35dfca79831a"} 3
`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
f, err := os.Open(tt.file)
f, err := os.Open(path.Join("../fixtures/shards/", tt.file))
if err != nil {
t.Fatal(err)
}
@ -63,15 +67,15 @@ elasticsearch_ilm_status{operation_mode="STOPPING"} 0
u, err := url.Parse(ts.URL)
if err != nil {
t.Fatal(err)
t.Fatalf("Failed to parse URL: %s", err)
}
c := NewIlmStatus(log.NewNopLogger(), http.DefaultClient, u)
s := NewShards(promslog.NewNopLogger(), http.DefaultClient, u)
if err != nil {
t.Fatal(err)
}
if err := testutil.CollectAndCompare(c, strings.NewReader(tt.want)); err != nil {
if err := testutil.CollectAndCompare(s, strings.NewReader(tt.want)); err != nil {
t.Fatal(err)
}
})

View File

@ -1,4 +1,4 @@
// Copyright 2022 The Prometheus Authors
// Copyright 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
@ -14,388 +14,244 @@
package collector
import (
"context"
"encoding/json"
"fmt"
"io"
"log/slog"
"net/http"
"net/url"
"path"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/prometheus/client_golang/prometheus"
)
type policyMetric struct {
Type prometheus.ValueType
Desc *prometheus.Desc
Value func(policyStats PolicyStats) float64
Labels func(policyStats PolicyStats) []string
}
type slmMetric struct {
Type prometheus.ValueType
Desc *prometheus.Desc
Value func(slmStats SLMStatsResponse) float64
}
type slmStatusMetric struct {
Type prometheus.ValueType
Desc *prometheus.Desc
Value func(slmStatus SLMStatusResponse, operationMode string) float64
Labels func(operationMode string) []string
}
var statuses = []string{"RUNNING", "STOPPING", "STOPPED"}
var (
defaultPolicyLabels = []string{"policy"}
defaultPolicyLabelValues = func(policyStats PolicyStats) []string {
return []string{policyStats.Policy}
}
slmRetentionRunsTotal = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "slm_stats", "retention_runs_total"),
"Total retention runs",
nil, nil,
)
slmRetentionFailedTotal = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "slm_stats", "retention_failed_total"),
"Total failed retention runs",
nil, nil,
)
slmRetentionTimedOutTotal = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "slm_stats", "retention_timed_out_total"),
"Total timed out retention runs",
nil, nil,
)
slmRetentionDeletionTimeSeconds = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "slm_stats", "retention_deletion_time_seconds"),
"Retention run deletion time",
nil, nil,
)
slmTotalSnapshotsTaken = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "slm_stats", "total_snapshots_taken_total"),
"Total snapshots taken",
nil, nil,
)
slmTotalSnapshotsFailed = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "slm_stats", "total_snapshots_failed_total"),
"Total snapshots failed",
nil, nil,
)
slmTotalSnapshotsDeleted = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "slm_stats", "total_snapshots_deleted_total"),
"Total snapshots deleted",
nil, nil,
)
slmTotalSnapshotsDeleteFailed = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "slm_stats", "total_snapshot_deletion_failures_total"),
"Total snapshot deletion failures",
nil, nil,
)
statuses = []string{"RUNNING", "STOPPING", "STOPPED"}
slmOperationMode = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "slm_stats", "operation_mode"),
"Operating status of SLM",
[]string{"operation_mode"}, nil,
)
slmSnapshotsTaken = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "slm_stats", "snapshots_taken_total"),
"Total snapshots taken",
[]string{"policy"}, nil,
)
slmSnapshotsFailed = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "slm_stats", "snapshots_failed_total"),
"Total snapshots failed",
[]string{"policy"}, nil,
)
slmSnapshotsDeleted = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "slm_stats", "snapshots_deleted_total"),
"Total snapshots deleted",
[]string{"policy"}, nil,
)
slmSnapshotsDeletionFailure = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "slm_stats", "snapshot_deletion_failures_total"),
"Total snapshot deletion failures",
[]string{"policy"}, nil,
)
)
func init() {
registerCollector("slm", defaultDisabled, NewSLM)
}
// SLM information struct
type SLM struct {
logger log.Logger
client *http.Client
url *url.URL
up prometheus.Gauge
totalScrapes, jsonParseFailures prometheus.Counter
slmMetrics []*slmMetric
policyMetrics []*policyMetric
slmStatusMetric *slmStatusMetric
logger *slog.Logger
hc *http.Client
u *url.URL
}
// NewSLM defines SLM Prometheus metrics
func NewSLM(logger log.Logger, client *http.Client, url *url.URL) *SLM {
func NewSLM(logger *slog.Logger, u *url.URL, hc *http.Client) (Collector, error) {
return &SLM{
logger: logger,
client: client,
url: url,
up: prometheus.NewGauge(prometheus.GaugeOpts{
Name: prometheus.BuildFQName(namespace, "slm_stats", "up"),
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.",
}),
jsonParseFailures: prometheus.NewCounter(prometheus.CounterOpts{
Name: prometheus.BuildFQName(namespace, "slm_stats", "json_parse_failures"),
Help: "Number of errors while parsing JSON.",
}),
slmMetrics: []*slmMetric{
{
Type: prometheus.CounterValue,
Desc: prometheus.NewDesc(
prometheus.BuildFQName(namespace, "slm_stats", "retention_runs_total"),
"Total retention runs",
nil, nil,
),
Value: func(slmStats SLMStatsResponse) float64 {
return float64(slmStats.RetentionRuns)
},
},
{
Type: prometheus.CounterValue,
Desc: prometheus.NewDesc(
prometheus.BuildFQName(namespace, "slm_stats", "retention_failed_total"),
"Total failed retention runs",
nil, nil,
),
Value: func(slmStats SLMStatsResponse) float64 {
return float64(slmStats.RetentionFailed)
},
},
{
Type: prometheus.CounterValue,
Desc: prometheus.NewDesc(
prometheus.BuildFQName(namespace, "slm_stats", "retention_timed_out_total"),
"Total timed out retention runs",
nil, nil,
),
Value: func(slmStats SLMStatsResponse) float64 {
return float64(slmStats.RetentionTimedOut)
},
},
{
Type: prometheus.GaugeValue,
Desc: prometheus.NewDesc(
prometheus.BuildFQName(namespace, "slm_stats", "retention_deletion_time_seconds"),
"Retention run deletion time",
nil, nil,
),
Value: func(slmStats SLMStatsResponse) float64 {
return float64(slmStats.RetentionDeletionTimeMillis) / 1000
},
},
{
Type: prometheus.CounterValue,
Desc: prometheus.NewDesc(
prometheus.BuildFQName(namespace, "slm_stats", "total_snapshots_taken_total"),
"Total snapshots taken",
nil, nil,
),
Value: func(slmStats SLMStatsResponse) float64 {
return float64(slmStats.TotalSnapshotsTaken)
},
},
{
Type: prometheus.CounterValue,
Desc: prometheus.NewDesc(
prometheus.BuildFQName(namespace, "slm_stats", "total_snapshots_failed_total"),
"Total snapshots failed",
nil, nil,
),
Value: func(slmStats SLMStatsResponse) float64 {
return float64(slmStats.TotalSnapshotsFailed)
},
},
{
Type: prometheus.CounterValue,
Desc: prometheus.NewDesc(
prometheus.BuildFQName(namespace, "slm_stats", "total_snapshots_deleted_total"),
"Total snapshots deleted",
nil, nil,
),
Value: func(slmStats SLMStatsResponse) float64 {
return float64(slmStats.TotalSnapshotsDeleted)
},
},
{
Type: prometheus.CounterValue,
Desc: prometheus.NewDesc(
prometheus.BuildFQName(namespace, "slm_stats", "total_snapshot_deletion_failures_total"),
"Total snapshot deletion failures",
nil, nil,
),
Value: func(slmStats SLMStatsResponse) float64 {
return float64(slmStats.TotalSnapshotDeletionFailures)
},
},
},
policyMetrics: []*policyMetric{
{
Type: prometheus.CounterValue,
Desc: prometheus.NewDesc(
prometheus.BuildFQName(namespace, "slm_stats", "snapshots_taken_total"),
"Total snapshots taken",
defaultPolicyLabels, nil,
),
Value: func(policyStats PolicyStats) float64 {
return float64(policyStats.SnapshotsTaken)
},
Labels: defaultPolicyLabelValues,
},
{
Type: prometheus.CounterValue,
Desc: prometheus.NewDesc(
prometheus.BuildFQName(namespace, "slm_stats", "snapshots_failed_total"),
"Total snapshots failed",
defaultPolicyLabels, nil,
),
Value: func(policyStats PolicyStats) float64 {
return float64(policyStats.SnapshotsFailed)
},
Labels: defaultPolicyLabelValues,
},
{
Type: prometheus.CounterValue,
Desc: prometheus.NewDesc(
prometheus.BuildFQName(namespace, "slm_stats", "snapshots_deleted_total"),
"Total snapshots deleted",
defaultPolicyLabels, nil,
),
Value: func(policyStats PolicyStats) float64 {
return float64(policyStats.SnapshotsDeleted)
},
Labels: defaultPolicyLabelValues,
},
{
Type: prometheus.CounterValue,
Desc: prometheus.NewDesc(
prometheus.BuildFQName(namespace, "slm_stats", "snapshot_deletion_failures_total"),
"Total snapshot deletion failures",
defaultPolicyLabels, nil,
),
Value: func(policyStats PolicyStats) float64 {
return float64(policyStats.SnapshotDeletionFailures)
},
Labels: defaultPolicyLabelValues,
},
},
slmStatusMetric: &slmStatusMetric{
Type: prometheus.GaugeValue,
Desc: prometheus.NewDesc(
prometheus.BuildFQName(namespace, "slm_stats", "operation_mode"),
"Operating status of SLM",
[]string{"operation_mode"}, nil,
),
Value: func(slmStatus SLMStatusResponse, operationMode string) float64 {
if slmStatus.OperationMode == operationMode {
return 1
}
return 0
},
},
}
hc: hc,
u: u,
}, nil
}
// Describe adds SLM metrics descriptions
func (s *SLM) Describe(ch chan<- *prometheus.Desc) {
ch <- s.slmStatusMetric.Desc
for _, metric := range s.slmMetrics {
ch <- metric.Desc
}
for _, metric := range s.policyMetrics {
ch <- metric.Desc
}
ch <- s.up.Desc()
ch <- s.totalScrapes.Desc()
ch <- s.jsonParseFailures.Desc()
// SLMStatsResponse is a representation of the SLM stats
type SLMStatsResponse struct {
RetentionRuns int64 `json:"retention_runs"`
RetentionFailed int64 `json:"retention_failed"`
RetentionTimedOut int64 `json:"retention_timed_out"`
RetentionDeletionTime string `json:"retention_deletion_time"`
RetentionDeletionTimeMillis int64 `json:"retention_deletion_time_millis"`
TotalSnapshotsTaken int64 `json:"total_snapshots_taken"`
TotalSnapshotsFailed int64 `json:"total_snapshots_failed"`
TotalSnapshotsDeleted int64 `json:"total_snapshots_deleted"`
TotalSnapshotDeletionFailures int64 `json:"total_snapshot_deletion_failures"`
PolicyStats []PolicyStats `json:"policy_stats"`
}
func (s *SLM) fetchAndDecodeSLMStats() (SLMStatsResponse, error) {
var ssr SLMStatsResponse
u := *s.url
u.Path = path.Join(u.Path, "/_slm/stats")
res, err := s.client.Get(u.String())
if err != nil {
return ssr, fmt.Errorf("failed to get slm 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(s.logger).Log(
"msg", "failed to close http.Client",
"err", err,
)
}
}()
if res.StatusCode != http.StatusOK {
return ssr, fmt.Errorf("HTTP Request failed with code %d", res.StatusCode)
}
bts, err := io.ReadAll(res.Body)
if err != nil {
s.jsonParseFailures.Inc()
return ssr, err
}
if err := json.Unmarshal(bts, &ssr); err != nil {
s.jsonParseFailures.Inc()
return ssr, err
}
return ssr, nil
// PolicyStats is a representation of SLM stats for specific policies
type PolicyStats struct {
Policy string `json:"policy"`
SnapshotsTaken int64 `json:"snapshots_taken"`
SnapshotsFailed int64 `json:"snapshots_failed"`
SnapshotsDeleted int64 `json:"snapshots_deleted"`
SnapshotDeletionFailures int64 `json:"snapshot_deletion_failures"`
}
func (s *SLM) fetchAndDecodeSLMStatus() (SLMStatusResponse, error) {
var ssr SLMStatusResponse
u := *s.url
u.Path = path.Join(u.Path, "/_slm/status")
res, err := s.client.Get(u.String())
if err != nil {
return ssr, fmt.Errorf("failed to get slm status 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(s.logger).Log(
"msg", "failed to close http.Client",
"err", err,
)
}
}()
if res.StatusCode != http.StatusOK {
return ssr, fmt.Errorf("HTTP Request failed with code %d", res.StatusCode)
}
bts, err := io.ReadAll(res.Body)
if err != nil {
s.jsonParseFailures.Inc()
return ssr, err
}
if err := json.Unmarshal(bts, &ssr); err != nil {
s.jsonParseFailures.Inc()
return ssr, err
}
return ssr, nil
// SLMStatusResponse is a representation of the SLM status
type SLMStatusResponse struct {
OperationMode string `json:"operation_mode"`
}
// Collect gets SLM metric values
func (s *SLM) Collect(ch chan<- prometheus.Metric) {
s.totalScrapes.Inc()
defer func() {
ch <- s.up
ch <- s.totalScrapes
ch <- s.jsonParseFailures
}()
func (s *SLM) Update(ctx context.Context, ch chan<- prometheus.Metric) error {
u := s.u.ResolveReference(&url.URL{Path: "/_slm/status"})
var slmStatusResp SLMStatusResponse
slmStatusResp, err := s.fetchAndDecodeSLMStatus()
resp, err := getURL(ctx, s.hc, s.logger, u.String())
if err != nil {
s.up.Set(0)
level.Warn(s.logger).Log(
"msg", "failed to fetch and decode slm status",
"err", err,
)
return
return err
}
slmStatsResp, err := s.fetchAndDecodeSLMStats()
err = json.Unmarshal(resp, &slmStatusResp)
if err != nil {
s.up.Set(0)
level.Warn(s.logger).Log(
"msg", "failed to fetch and decode slm stats",
"err", err,
)
return
return err
}
s.up.Set(1)
u = s.u.ResolveReference(&url.URL{Path: "/_slm/stats"})
var slmStatsResp SLMStatsResponse
resp, err = getURL(ctx, s.hc, s.logger, u.String())
if err != nil {
return err
}
err = json.Unmarshal(resp, &slmStatsResp)
if err != nil {
return err
}
for _, status := range statuses {
var value float64
if slmStatusResp.OperationMode == status {
value = 1
}
ch <- prometheus.MustNewConstMetric(
s.slmStatusMetric.Desc,
s.slmStatusMetric.Type,
s.slmStatusMetric.Value(slmStatusResp, status),
slmOperationMode,
prometheus.GaugeValue,
value,
status,
)
}
for _, metric := range s.slmMetrics {
ch <- prometheus.MustNewConstMetric(
slmRetentionRunsTotal,
prometheus.CounterValue,
float64(slmStatsResp.RetentionRuns),
)
ch <- prometheus.MustNewConstMetric(
slmRetentionFailedTotal,
prometheus.CounterValue,
float64(slmStatsResp.RetentionFailed),
)
ch <- prometheus.MustNewConstMetric(
slmRetentionTimedOutTotal,
prometheus.CounterValue,
float64(slmStatsResp.RetentionTimedOut),
)
ch <- prometheus.MustNewConstMetric(
slmRetentionDeletionTimeSeconds,
prometheus.GaugeValue,
float64(slmStatsResp.RetentionDeletionTimeMillis)/1000,
)
ch <- prometheus.MustNewConstMetric(
slmTotalSnapshotsTaken,
prometheus.CounterValue,
float64(slmStatsResp.TotalSnapshotsTaken),
)
ch <- prometheus.MustNewConstMetric(
slmTotalSnapshotsFailed,
prometheus.CounterValue,
float64(slmStatsResp.TotalSnapshotsFailed),
)
ch <- prometheus.MustNewConstMetric(
slmTotalSnapshotsDeleted,
prometheus.CounterValue,
float64(slmStatsResp.TotalSnapshotsDeleted),
)
ch <- prometheus.MustNewConstMetric(
slmTotalSnapshotsDeleteFailed,
prometheus.CounterValue,
float64(slmStatsResp.TotalSnapshotDeletionFailures),
)
for _, policy := range slmStatsResp.PolicyStats {
ch <- prometheus.MustNewConstMetric(
metric.Desc,
metric.Type,
metric.Value(slmStatsResp),
slmSnapshotsTaken,
prometheus.CounterValue,
float64(policy.SnapshotsTaken),
policy.Policy,
)
ch <- prometheus.MustNewConstMetric(
slmSnapshotsFailed,
prometheus.CounterValue,
float64(policy.SnapshotsFailed),
policy.Policy,
)
ch <- prometheus.MustNewConstMetric(
slmSnapshotsDeleted,
prometheus.CounterValue,
float64(policy.SnapshotsDeleted),
policy.Policy,
)
ch <- prometheus.MustNewConstMetric(
slmSnapshotsDeletionFailure,
prometheus.CounterValue,
float64(policy.SnapshotDeletionFailures),
policy.Policy,
)
}
for _, metric := range s.policyMetrics {
for _, policy := range slmStatsResp.PolicyStats {
ch <- prometheus.MustNewConstMetric(
metric.Desc,
metric.Type,
metric.Value(policy),
metric.Labels(policy)...,
)
}
}
return nil
}

View File

@ -1,42 +0,0 @@
// 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
// SLMStatsResponse is a representation of the SLM stats
type SLMStatsResponse struct {
RetentionRuns int64 `json:"retention_runs"`
RetentionFailed int64 `json:"retention_failed"`
RetentionTimedOut int64 `json:"retention_timed_out"`
RetentionDeletionTime string `json:"retention_deletion_time"`
RetentionDeletionTimeMillis int64 `json:"retention_deletion_time_millis"`
TotalSnapshotsTaken int64 `json:"total_snapshots_taken"`
TotalSnapshotsFailed int64 `json:"total_snapshots_failed"`
TotalSnapshotsDeleted int64 `json:"total_snapshots_deleted"`
TotalSnapshotDeletionFailures int64 `json:"total_snapshot_deletion_failures"`
PolicyStats []PolicyStats `json:"policy_stats"`
}
// PolicyStats is a representation of SLM stats for specific policies
type PolicyStats struct {
Policy string `json:"policy"`
SnapshotsTaken int64 `json:"snapshots_taken"`
SnapshotsFailed int64 `json:"snapshots_failed"`
SnapshotsDeleted int64 `json:"snapshots_deleted"`
SnapshotDeletionFailures int64 `json:"snapshot_deletion_failures"`
}
// SLMStatusResponse is a representation of the SLM status
type SLMStatusResponse struct {
OperationMode string `json:"operation_mode"`
}

View File

@ -1,4 +1,4 @@
// Copyright 2022 The Prometheus Authors
// Copyright 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
@ -14,13 +14,17 @@
package collector
import (
"fmt"
"io"
"net/http"
"net/http/httptest"
"net/url"
"os"
"path"
"strings"
"testing"
"github.com/go-kit/log"
"github.com/prometheus/client_golang/prometheus/testutil"
"github.com/prometheus/common/promslog"
)
func TestSLM(t *testing.T) {
@ -31,35 +35,102 @@ func TestSLM(t *testing.T) {
// curl -XPUT http://127.0.0.1:9200/_slm/policy/everything -H 'Content-Type: application/json' -d '{"schedule":"0 */15 * * * ?","name":"<everything-{now/d}>","repository":"my_repository","config":{"indices":".*","include_global_state":true,"ignore_unavailable":true},"retention":{"expire_after":"7d"}}'
// curl http://127.0.0.1:9200/_slm/stats (Numbers manually tweaked)
tcs := map[string]string{
"7.15.0": `{"retention_runs":9,"retention_failed":0,"retention_timed_out":0,"retention_deletion_time":"1.2m","retention_deletion_time_millis":72491,"total_snapshots_taken":103,"total_snapshots_failed":2,"total_snapshots_deleted":20,"total_snapshot_deletion_failures":0,"policy_stats":[{"policy":"everything","snapshots_taken":50,"snapshots_failed":2,"snapshots_deleted":20,"snapshot_deletion_failures":0}]}`,
}
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 := NewSLM(log.NewNopLogger(), http.DefaultClient, u)
stats, err := s.fetchAndDecodeSLMStats()
if err != nil {
t.Fatalf("Failed to fetch or decode snapshots stats: %s", err)
}
t.Logf("[%s] SLM Response: %+v", ver, stats)
slmStats := stats
policyStats := stats.PolicyStats[0]
if slmStats.TotalSnapshotsTaken != 103 {
t.Errorf("Bad number of total snapshots taken")
}
if policyStats.SnapshotsTaken != 50 {
t.Errorf("Bad number of policy snapshots taken")
}
tests := []struct {
name string
file string
want string
}{
{
name: "7.15.0",
file: "7.15.0.json",
want: `# HELP elasticsearch_slm_stats_operation_mode Operating status of SLM
# TYPE elasticsearch_slm_stats_operation_mode gauge
elasticsearch_slm_stats_operation_mode{operation_mode="RUNNING"} 0
elasticsearch_slm_stats_operation_mode{operation_mode="STOPPED"} 0
elasticsearch_slm_stats_operation_mode{operation_mode="STOPPING"} 0
# HELP elasticsearch_slm_stats_retention_deletion_time_seconds Retention run deletion time
# TYPE elasticsearch_slm_stats_retention_deletion_time_seconds gauge
elasticsearch_slm_stats_retention_deletion_time_seconds 72.491
# HELP elasticsearch_slm_stats_retention_failed_total Total failed retention runs
# TYPE elasticsearch_slm_stats_retention_failed_total counter
elasticsearch_slm_stats_retention_failed_total 0
# HELP elasticsearch_slm_stats_retention_runs_total Total retention runs
# TYPE elasticsearch_slm_stats_retention_runs_total counter
elasticsearch_slm_stats_retention_runs_total 9
# HELP elasticsearch_slm_stats_retention_timed_out_total Total timed out retention runs
# TYPE elasticsearch_slm_stats_retention_timed_out_total counter
elasticsearch_slm_stats_retention_timed_out_total 0
# HELP elasticsearch_slm_stats_snapshot_deletion_failures_total Total snapshot deletion failures
# TYPE elasticsearch_slm_stats_snapshot_deletion_failures_total counter
elasticsearch_slm_stats_snapshot_deletion_failures_total{policy="everything"} 0
# HELP elasticsearch_slm_stats_snapshots_deleted_total Total snapshots deleted
# TYPE elasticsearch_slm_stats_snapshots_deleted_total counter
elasticsearch_slm_stats_snapshots_deleted_total{policy="everything"} 20
# HELP elasticsearch_slm_stats_snapshots_failed_total Total snapshots failed
# TYPE elasticsearch_slm_stats_snapshots_failed_total counter
elasticsearch_slm_stats_snapshots_failed_total{policy="everything"} 2
# HELP elasticsearch_slm_stats_snapshots_taken_total Total snapshots taken
# TYPE elasticsearch_slm_stats_snapshots_taken_total counter
elasticsearch_slm_stats_snapshots_taken_total{policy="everything"} 50
# HELP elasticsearch_slm_stats_total_snapshot_deletion_failures_total Total snapshot deletion failures
# TYPE elasticsearch_slm_stats_total_snapshot_deletion_failures_total counter
elasticsearch_slm_stats_total_snapshot_deletion_failures_total 0
# HELP elasticsearch_slm_stats_total_snapshots_deleted_total Total snapshots deleted
# TYPE elasticsearch_slm_stats_total_snapshots_deleted_total counter
elasticsearch_slm_stats_total_snapshots_deleted_total 20
# HELP elasticsearch_slm_stats_total_snapshots_failed_total Total snapshots failed
# TYPE elasticsearch_slm_stats_total_snapshots_failed_total counter
elasticsearch_slm_stats_total_snapshots_failed_total 2
# HELP elasticsearch_slm_stats_total_snapshots_taken_total Total snapshots taken
# TYPE elasticsearch_slm_stats_total_snapshots_taken_total counter
elasticsearch_slm_stats_total_snapshots_taken_total 103
`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
fStatsPath := path.Join("../fixtures/slm/stats/", tt.file)
fStats, err := os.Open(fStatsPath)
if err != nil {
t.Fatal(err)
}
defer fStats.Close()
fStatusPath := path.Join("../fixtures/slm/status/", tt.file)
fStatus, err := os.Open(fStatusPath)
if err != nil {
t.Fatal(err)
}
defer fStatus.Close()
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.RequestURI {
case "/_slm/stats":
io.Copy(w, fStats)
return
case "/_slm/status":
io.Copy(w, fStatus)
return
}
http.Error(w, "Not Found", http.StatusNotFound)
}))
defer ts.Close()
u, err := url.Parse(ts.URL)
if err != nil {
t.Fatalf("Failed to parse URL: %s", err)
}
s, err := NewSLM(promslog.NewNopLogger(), u, http.DefaultClient)
if err != nil {
t.Fatal(err)
}
if err := testutil.CollectAndCompare(wrapCollector{s}, strings.NewReader(tt.want)); err != nil {
t.Fatal(err)
}
})
}
}

View File

@ -1,4 +1,4 @@
// Copyright 2021 The Prometheus Authors
// Copyright 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
@ -17,11 +17,11 @@ import (
"context"
"encoding/json"
"fmt"
"log/slog"
"net/http"
"net/url"
"path"
"github.com/go-kit/log"
"github.com/prometheus/client_golang/prometheus"
)
@ -96,13 +96,13 @@ func init() {
// Snapshots information struct
type Snapshots struct {
logger log.Logger
logger *slog.Logger
hc *http.Client
u *url.URL
}
// NewSnapshots defines Snapshots Prometheus metrics
func NewSnapshots(logger log.Logger, u *url.URL, hc *http.Client) (Collector, error) {
func NewSnapshots(logger *slog.Logger, u *url.URL, hc *http.Client) (Collector, error) {
return &Snapshots{
logger: logger,
u: u,
@ -143,7 +143,6 @@ func (c *Snapshots) Update(ctx context.Context, ch chan<- prometheus.Metric) err
// Snapshots stats
for repositoryName, snapshotStats := range snapshotsStatsResp {
ch <- prometheus.MustNewConstMetric(
numSnapshots,
prometheus.GaugeValue,
@ -164,7 +163,7 @@ func (c *Snapshots) Update(ctx context.Context, ch chan<- prometheus.Metric) err
latest := float64(0)
for i := len(snapshotStats.Snapshots) - 1; i >= 0; i-- {
var snap = snapshotStats.Snapshots[i]
snap := snapshotStats.Snapshots[i]
if snap.State == "SUCCESS" || snap.State == "PARTIAL" {
latest = float64(snap.StartTimeInMillis / 1000)
break

View File

@ -1,4 +1,4 @@
// Copyright 2021 The Prometheus Authors
// Copyright 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

View File

@ -1,4 +1,4 @@
// Copyright 2021 The Prometheus Authors
// Copyright 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
@ -23,8 +23,8 @@ import (
"strings"
"testing"
"github.com/go-kit/log"
"github.com/prometheus/client_golang/prometheus/testutil"
"github.com/prometheus/common/promslog"
)
func TestSnapshots(t *testing.T) {
@ -209,7 +209,7 @@ func TestSnapshots(t *testing.T) {
t.Fatal(err)
}
c, err := NewSnapshots(log.NewNopLogger(), u, http.DefaultClient)
c, err := NewSnapshots(promslog.NewNopLogger(), u, http.DefaultClient)
if err != nil {
t.Fatal(err)
}

142
collector/tasks.go Normal file
View File

@ -0,0 +1,142 @@
// Copyright 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 (
"context"
"encoding/json"
"fmt"
"io"
"log/slog"
"net/http"
"net/url"
"github.com/alecthomas/kingpin/v2"
"github.com/prometheus/client_golang/prometheus"
)
// filterByTask global required because collector interface doesn't expose any way to take
// constructor args.
var actionFilter string
var taskActionDesc = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "task_stats", "action"),
"Number of tasks of a certain action",
[]string{"action"}, nil)
func init() {
kingpin.Flag("tasks.actions",
"Filter on task actions. Used in same way as Task API actions param").
Default("indices:*").StringVar(&actionFilter)
registerCollector("tasks", defaultDisabled, NewTaskCollector)
}
// Task Information Struct
type TaskCollector struct {
logger *slog.Logger
hc *http.Client
u *url.URL
}
// NewTaskCollector defines Task Prometheus metrics
func NewTaskCollector(logger *slog.Logger, u *url.URL, hc *http.Client) (Collector, error) {
logger.Info("task collector created",
"actionFilter", actionFilter,
)
return &TaskCollector{
logger: logger,
hc: hc,
u: u,
}, nil
}
func (t *TaskCollector) Update(ctx context.Context, ch chan<- prometheus.Metric) error {
tasks, err := t.fetchTasks(ctx)
if err != nil {
return fmt.Errorf("failed to fetch and decode task stats: %w", err)
}
stats := AggregateTasks(tasks)
for action, count := range stats.CountByAction {
ch <- prometheus.MustNewConstMetric(
taskActionDesc,
prometheus.GaugeValue,
float64(count),
action,
)
}
return nil
}
func (t *TaskCollector) fetchTasks(_ context.Context) (tasksResponse, error) {
u := t.u.ResolveReference(&url.URL{Path: "_tasks"})
q := u.Query()
q.Set("group_by", "none")
q.Set("actions", actionFilter)
u.RawQuery = q.Encode()
var tr tasksResponse
res, err := t.hc.Get(u.String())
if err != nil {
return tr, 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 {
t.logger.Warn(
"failed to close http.Client",
"err", err,
)
}
}()
if res.StatusCode != http.StatusOK {
return tr, fmt.Errorf("HTTP Request to %v failed with code %d", u.String(), res.StatusCode)
}
bts, err := io.ReadAll(res.Body)
if err != nil {
return tr, err
}
err = json.Unmarshal(bts, &tr)
return tr, err
}
// tasksResponse is a representation of the Task management API.
type tasksResponse struct {
Tasks []taskResponse `json:"tasks"`
}
// taskResponse is a representation of the individual task item returned by task API endpoint.
//
// We only parse a very limited amount of this API for use in aggregation.
type taskResponse struct {
Action string `json:"action"`
}
type aggregatedTaskStats struct {
CountByAction map[string]int64
}
func AggregateTasks(t tasksResponse) aggregatedTaskStats {
actions := map[string]int64{}
for _, task := range t.Tasks {
actions[task.Action]++
}
return aggregatedTaskStats{CountByAction: actions}
}

78
collector/tasks_test.go Normal file
View File

@ -0,0 +1,78 @@
// Copyright 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"
"strings"
"testing"
"github.com/prometheus/client_golang/prometheus/testutil"
"github.com/prometheus/common/promslog"
)
func TestTasks(t *testing.T) {
// Test data was collected by running the following:
// # create container
// docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.17.11
// sleep 15
// # start some busy work in background
// for i in $(seq 1 500)
// do
// curl -o /dev/null -sX POST "localhost:9200/a1/_doc" -H 'Content-Type: application/json' -d'{"a1": "'"$i"'"}'
// sleep .01
// curl -o /dev/null -sX POST "localhost:9200/a1/_doc" -H 'Content-Type: application/json' -d'{"a2": "'"$i"'"}'
// sleep .01
// curl -o /dev/null -sX POST "localhost:9200/a1/_doc" -H 'Content-Type: application/json' -d'{"a3": "'"$i"'"}'
// sleep .01
// done &
// # try and collect a good sample
// curl -X GET 'localhost:9200/_tasks?group_by=none&actions=indices:*'
// # cleanup
// docker rm --force elasticsearch
tcs := map[string]string{
"7.17": `{"tasks":[{"node":"9lWCm1y_QkujaAg75bVx7A","id":70,"type":"transport","action":"indices:admin/index_template/put","start_time_in_millis":1695900464655,"running_time_in_nanos":308640039,"cancellable":false,"headers":{}},{"node":"9lWCm1y_QkujaAg75bVx7A","id":73,"type":"transport","action":"indices:admin/index_template/put","start_time_in_millis":1695900464683,"running_time_in_nanos":280672000,"cancellable":false,"headers":{}},{"node":"9lWCm1y_QkujaAg75bVx7A","id":76,"type":"transport","action":"indices:admin/index_template/put","start_time_in_millis":1695900464711,"running_time_in_nanos":253247906,"cancellable":false,"headers":{}},{"node":"9lWCm1y_QkujaAg75bVx7A","id":93,"type":"transport","action":"indices:admin/index_template/put","start_time_in_millis":1695900464904,"running_time_in_nanos":60230460,"cancellable":false,"headers":{}},{"node":"9lWCm1y_QkujaAg75bVx7A","id":50,"type":"transport","action":"indices:data/write/index","start_time_in_millis":1695900464229,"running_time_in_nanos":734480468,"cancellable":false,"headers":{}},{"node":"9lWCm1y_QkujaAg75bVx7A","id":51,"type":"transport","action":"indices:admin/auto_create","start_time_in_millis":1695900464235,"running_time_in_nanos":729223933,"cancellable":false,"headers":{}}]}`,
}
want := `# HELP elasticsearch_task_stats_action Number of tasks of a certain action
# TYPE elasticsearch_task_stats_action gauge
elasticsearch_task_stats_action{action="indices:admin/auto_create"} 1
elasticsearch_task_stats_action{action="indices:admin/index_template/put"} 4
elasticsearch_task_stats_action{action="indices:data/write/index"} 1
`
for ver, out := range tcs {
t.Run(ver, func(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *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, err := NewTaskCollector(promslog.NewNopLogger(), u, ts.Client())
if err != nil {
t.Fatalf("Failed to create collector: %v", err)
}
if err := testutil.CollectAndCompare(wrapCollector{c}, strings.NewReader(want)); err != nil {
t.Fatalf("Metrics did not match: %v", err)
}
})
}
}

View File

@ -1,4 +1,4 @@
// Copyright 2023 The Prometheus Authors
// Copyright 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
@ -17,13 +17,11 @@ import (
"context"
"fmt"
"io"
"log/slog"
"net/http"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
)
func getURL(ctx context.Context, hc *http.Client, log log.Logger, u string) ([]byte, error) {
func getURL(ctx context.Context, hc *http.Client, log *slog.Logger, u string) ([]byte, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil)
if err != nil {
return nil, err
@ -31,14 +29,14 @@ func getURL(ctx context.Context, hc *http.Client, log log.Logger, u string) ([]b
resp, err := hc.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to get %s: %v", u, err)
return nil, err
}
defer func() {
err = resp.Body.Close()
if err != nil {
level.Warn(log).Log(
"msg", "failed to close response body",
log.Warn(
"failed to close response body",
"err", err,
)
}
@ -55,3 +53,11 @@ func getURL(ctx context.Context, hc *http.Client, log log.Logger, u string) ([]b
return b, nil
}
// bool2Float converts a bool to a float64. True is 1, false is 0.
func bool2Float(managed bool) float64 {
if managed {
return 1
}
return 0
}

137
config/config.go Normal file
View File

@ -0,0 +1,137 @@
// Copyright 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 config
import (
"fmt"
"os"
"strings"
"go.yaml.in/yaml/v3"
)
// Config represents the YAML configuration file structure.
type Config struct {
AuthModules map[string]AuthModule `yaml:"auth_modules"`
}
type AuthModule struct {
Type string `yaml:"type"`
UserPass *UserPassConfig `yaml:"userpass,omitempty"`
APIKey string `yaml:"apikey,omitempty"`
AWS *AWSConfig `yaml:"aws,omitempty"`
TLS *TLSConfig `yaml:"tls,omitempty"`
Options map[string]string `yaml:"options,omitempty"`
}
// AWSConfig contains settings for SigV4 authentication.
type AWSConfig struct {
Region string `yaml:"region,omitempty"`
RoleARN string `yaml:"role_arn,omitempty"`
}
// TLSConfig allows per-target TLS options.
type TLSConfig struct {
CAFile string `yaml:"ca_file,omitempty"`
CertFile string `yaml:"cert_file,omitempty"`
KeyFile string `yaml:"key_file,omitempty"`
InsecureSkipVerify bool `yaml:"insecure_skip_verify,omitempty"`
}
type UserPassConfig struct {
Username string `yaml:"username"`
Password string `yaml:"password"`
}
// validate ensures every auth module has the required fields according to its type.
func (c *Config) validate() error {
for name, am := range c.AuthModules {
// Validate fields based on auth type
switch strings.ToLower(am.Type) {
case "userpass":
if am.UserPass == nil || am.UserPass.Username == "" || am.UserPass.Password == "" {
return fmt.Errorf("auth_module %s type userpass requires username and password", name)
}
case "apikey":
if am.APIKey == "" {
return fmt.Errorf("auth_module %s type apikey requires apikey", name)
}
case "aws":
// No strict validation: region can come from environment/defaults; role_arn is optional.
case "tls":
// TLS auth type means client certificate authentication only (no other auth)
if am.TLS == nil {
return fmt.Errorf("auth_module %s type tls requires tls configuration section", name)
}
if am.TLS.CertFile == "" || am.TLS.KeyFile == "" {
return fmt.Errorf("auth_module %s type tls requires cert_file and key_file for client certificate authentication", name)
}
// Validate that other auth fields are not set when using TLS auth type
if am.UserPass != nil {
return fmt.Errorf("auth_module %s type tls cannot have userpass configuration", name)
}
if am.APIKey != "" {
return fmt.Errorf("auth_module %s type tls cannot have apikey", name)
}
if am.AWS != nil {
return fmt.Errorf("auth_module %s type tls cannot have aws configuration", name)
}
default:
return fmt.Errorf("auth_module %s has unsupported type %s", name, am.Type)
}
// Validate TLS configuration (optional for all auth types, provides transport security)
if am.TLS != nil {
// For cert-based auth (type: tls), cert and key are required
// For other auth types, TLS config is optional and used for transport security
if strings.ToLower(am.Type) != "tls" {
// For non-TLS auth types, if cert/key are provided, both must be present
if (am.TLS.CertFile != "") != (am.TLS.KeyFile != "") {
return fmt.Errorf("auth_module %s: if providing client certificate, both cert_file and key_file must be specified", name)
}
}
// Validate file accessibility
for fileType, path := range map[string]string{
"ca_file": am.TLS.CAFile,
"cert_file": am.TLS.CertFile,
"key_file": am.TLS.KeyFile,
} {
if path == "" {
continue
}
if _, err := os.Stat(path); err != nil {
return fmt.Errorf("auth_module %s: %s '%s' not accessible: %w", name, fileType, path, err)
}
}
}
}
return nil
}
// LoadConfig reads, parses, and validates the YAML config file.
func LoadConfig(path string) (*Config, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, err
}
var cfg Config
if err := yaml.Unmarshal(data, &cfg); err != nil {
return nil, err
}
if err := cfg.validate(); err != nil {
return nil, err
}
return &cfg, nil
}

183
config/config_test.go Normal file
View File

@ -0,0 +1,183 @@
// Copyright 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 config
import (
"os"
"testing"
)
func mustTempFile(t *testing.T) string {
f, err := os.CreateTemp(t.TempDir(), "pem-*.crt")
if err != nil {
t.Fatalf("temp file: %v", err)
}
f.Close()
// Ensure temp file is removed even if created outside of test's TempDir semantics change
path := f.Name()
t.Cleanup(func() { _ = os.Remove(path) })
return path
}
// ---------------------------- Positive cases ----------------------------
func TestLoadConfigPositiveVariants(t *testing.T) {
ca := mustTempFile(t)
cert := mustTempFile(t)
key := mustTempFile(t)
positive := []struct {
name string
yaml string
}{{
"userpass",
`auth_modules:
basic:
type: userpass
userpass:
username: u
password: p`,
}, {
"userpass-with-tls",
`auth_modules:
basic:
type: userpass
userpass:
username: u
password: p
tls:
ca_file: ` + ca + `
insecure_skip_verify: true`,
}, {
"apikey",
`auth_modules:
key:
type: apikey
apikey: ZXhhbXBsZQ==`,
}, {
"apikey-with-tls",
`auth_modules:
key:
type: apikey
apikey: ZXhhbXBsZQ==
tls:
ca_file: ` + ca + `
cert_file: ` + cert + `
key_file: ` + key + ``,
}, {
"aws-with-tls",
`auth_modules:
awsmod:
type: aws
aws:
region: us-east-1
tls:
insecure_skip_verify: true`,
}, {
"tls-only",
`auth_modules:
pki:
type: tls
tls:
ca_file: ` + ca + `
cert_file: ` + cert + `
key_file: ` + key + ``,
}}
for _, c := range positive {
tmp, _ := os.CreateTemp(t.TempDir(), "cfg-*.yml")
_, _ = tmp.WriteString(c.yaml)
_ = tmp.Close()
t.Cleanup(func() { _ = os.Remove(tmp.Name()) })
if _, err := LoadConfig(tmp.Name()); err != nil {
t.Fatalf("%s: expected success, got %v", c.name, err)
}
}
}
// ---------------------------- Negative cases ----------------------------
func TestLoadConfigNegativeVariants(t *testing.T) {
cert := mustTempFile(t)
key := mustTempFile(t)
negative := []struct {
name string
yaml string
}{{
"userpassMissingPassword",
`auth_modules:
bad:
type: userpass
userpass: {username: u}`,
}, {
"tlsMissingCert",
`auth_modules:
bad:
type: tls
tls: {key_file: ` + key + `}`,
}, {
"tlsMissingKey",
`auth_modules:
bad:
type: tls
tls: {cert_file: ` + cert + `}`,
}, {
"tlsMissingConfig",
`auth_modules:
bad:
type: tls`,
}, {
"tlsWithUserpass",
`auth_modules:
bad:
type: tls
tls: {cert_file: ` + cert + `, key_file: ` + key + `}
userpass: {username: u, password: p}`,
}, {
"tlsWithAPIKey",
`auth_modules:
bad:
type: tls
tls: {cert_file: ` + cert + `, key_file: ` + key + `}
apikey: ZXhhbXBsZQ==`,
}, {
"tlsWithAWS",
`auth_modules:
bad:
type: tls
tls: {cert_file: ` + cert + `, key_file: ` + key + `}
aws: {region: us-east-1}`,
}, {
"tlsIncompleteCert",
`auth_modules:
bad:
type: apikey
apikey: ZXhhbXBsZQ==
tls: {cert_file: ` + cert + `}`,
}, {
"unsupportedType",
`auth_modules:
bad:
type: foobar`,
}}
for _, c := range negative {
tmp, _ := os.CreateTemp(t.TempDir(), "cfg-*.yml")
_, _ = tmp.WriteString(c.yaml)
_ = tmp.Close()
t.Cleanup(func() { _ = os.Remove(tmp.Name()) })
if _, err := LoadConfig(tmp.Name()); err == nil {
t.Fatalf("%s: expected validation error, got none", c.name)
}
}
}

View File

@ -0,0 +1,29 @@
# Elasticsearch Exporter Mixin
This is a mixin for the elasticsearch_exporter to define dashboards, alerts, and monitoring queries for use with this exporter.
Good example of upstream mixin for reference: https://github.com/kubernetes-monitoring/kubernetes-mixin
## Development
### JSONNET
https://jsonnet.org/
```go install github.com/google/go-jsonnet/cmd/jsonnet@latest```
### JSONNET BUNDLER
jsonnet bundler is a package manager for jsonnet
https://github.com/jsonnet-bundler/jsonnet-bundler
```go install -a github.com/jsonnet-bundler/jsonnet-bundler/cmd/jb@latest```
### Grafonnet
Grafana libraries for jsonnet: https://grafana.github.io/grafonnet/
```jb install github.com/grafana/grafonnet/gen/grafonnet-latest@main```
### Run the build
```bash
./scripts/compile-mixin.sh
```

View File

@ -0,0 +1 @@
{}

View File

@ -0,0 +1,687 @@
{
"graphTooltip": 1,
"panels": [
{
"collapsed": false,
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 0
},
"id": 1,
"panels": [ ],
"title": "Overview",
"type": "row"
},
{
"datasource": {
"type": "datasource",
"uid": "-- Mixed --"
},
"gridPos": {
"h": 4,
"w": 8,
"x": 0,
"y": 1
},
"id": 2,
"pluginVersion": "v10.4.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "$datasource"
},
"expr": "sum(\n elasticsearch_cluster_health_number_of_nodes{cluster=~\"$cluster\"}\n)\n"
}
],
"title": "Nodes",
"type": "stat"
},
{
"datasource": {
"type": "datasource",
"uid": "-- Mixed --"
},
"gridPos": {
"h": 4,
"w": 8,
"x": 8,
"y": 1
},
"id": 3,
"pluginVersion": "v10.4.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "$datasource"
},
"expr": "sum(\n elasticsearch_cluster_health_number_of_data_nodes{cluster=~\"$cluster\"}\n)\n"
}
],
"title": "Data Nodes",
"type": "stat"
},
{
"datasource": {
"type": "datasource",
"uid": "-- Mixed --"
},
"gridPos": {
"h": 4,
"w": 8,
"x": 16,
"y": 1
},
"id": 4,
"pluginVersion": "v10.4.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "$datasource"
},
"expr": "sum(\n elasticsearch_cluster_health_number_of_pending_tasks{cluster=~\"$cluster\"}\n)\n"
}
],
"title": "Pending Tasks",
"type": "stat"
},
{
"collapsed": false,
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 5
},
"id": 5,
"panels": [ ],
"title": "Shards",
"type": "row"
},
{
"datasource": {
"type": "datasource",
"uid": "-- Mixed --"
},
"gridPos": {
"h": 4,
"w": 4,
"x": 0,
"y": 6
},
"id": 6,
"pluginVersion": "v10.4.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "$datasource"
},
"expr": "sum(\n elasticsearch_cluster_health_active_shards{cluster=~\"$cluster\"}\n)\n"
}
],
"title": "Active",
"type": "stat"
},
{
"datasource": {
"type": "datasource",
"uid": "-- Mixed --"
},
"gridPos": {
"h": 4,
"w": 4,
"x": 4,
"y": 6
},
"id": 7,
"pluginVersion": "v10.4.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "$datasource"
},
"expr": "sum(\n elasticsearch_cluster_health_active_primary_shards{cluster=~\"$cluster\"}\n)\n"
}
],
"title": "Active Primary",
"type": "stat"
},
{
"datasource": {
"type": "datasource",
"uid": "-- Mixed --"
},
"gridPos": {
"h": 4,
"w": 4,
"x": 8,
"y": 6
},
"id": 8,
"pluginVersion": "v10.4.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "$datasource"
},
"expr": "sum(\n elasticsearch_cluster_health_initializing_shards{cluster=~\"$cluster\"}\n)\n"
}
],
"title": "Initializing",
"type": "stat"
},
{
"datasource": {
"type": "datasource",
"uid": "-- Mixed --"
},
"gridPos": {
"h": 4,
"w": 4,
"x": 12,
"y": 6
},
"id": 9,
"pluginVersion": "v10.4.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "$datasource"
},
"expr": "sum(\n elasticsearch_cluster_health_reloacting_shards{cluster=~\"$cluster\"}\n)\n"
}
],
"title": "Relocating",
"type": "stat"
},
{
"datasource": {
"type": "datasource",
"uid": "-- Mixed --"
},
"gridPos": {
"h": 4,
"w": 4,
"x": 16,
"y": 6
},
"id": 10,
"pluginVersion": "v10.4.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "$datasource"
},
"expr": "sum(\n elasticsearch_cluster_health_unassigned_shards{cluster=~\"$cluster\"}\n)\n"
}
],
"title": "Unassigned",
"type": "stat"
},
{
"datasource": {
"type": "datasource",
"uid": "-- Mixed --"
},
"gridPos": {
"h": 4,
"w": 4,
"x": 20,
"y": 6
},
"id": 11,
"pluginVersion": "v10.4.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "$datasource"
},
"expr": "sum(\n elasticsearch_cluster_health_delayed_unassigned_shards{cluster=~\"$cluster\"}\n)\n"
}
],
"title": "DelayedUnassigned",
"type": "stat"
},
{
"collapsed": false,
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 10
},
"id": 12,
"panels": [ ],
"title": "Documents",
"type": "row"
},
{
"datasource": {
"type": "datasource",
"uid": "-- Mixed --"
},
"gridPos": {
"h": 4,
"w": 4,
"x": 0,
"y": 11
},
"id": 13,
"pluginVersion": "v10.4.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "$datasource"
},
"expr": "elasticsearch_indices_docs{cluster=~\"$cluster\"}\n"
}
],
"title": "Indexed Documents",
"type": "timeseries"
},
{
"datasource": {
"type": "datasource",
"uid": "-- Mixed --"
},
"fieldConfig": {
"defaults": {
"unit": "bytes"
}
},
"gridPos": {
"h": 4,
"w": 4,
"x": 4,
"y": 11
},
"id": 14,
"pluginVersion": "v10.4.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "$datasource"
},
"expr": "elasticsearch_indices_store_size_bytes{cluster=~\"$cluster\"}\n"
}
],
"title": "Index Size",
"type": "timeseries"
},
{
"datasource": {
"type": "datasource",
"uid": "-- Mixed --"
},
"gridPos": {
"h": 4,
"w": 4,
"x": 8,
"y": 11
},
"id": 15,
"pluginVersion": "v10.4.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "$datasource"
},
"expr": "rate(elasticsearch_indices_indexing_index_total{cluster=~\"$cluster\"}[$__rate_interval])\n",
"legendFormat": "{{name}}"
}
],
"title": "Index Rate",
"type": "timeseries"
},
{
"datasource": {
"type": "datasource",
"uid": "-- Mixed --"
},
"gridPos": {
"h": 4,
"w": 4,
"x": 12,
"y": 11
},
"id": 16,
"pluginVersion": "v10.4.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "$datasource"
},
"expr": "rate(elasticsearch_indices_search_query_total{cluster=~\"$cluster\"}[$__rate_interval])\n",
"legendFormat": "{{name}}"
}
],
"title": "Query Rate",
"type": "timeseries"
},
{
"datasource": {
"type": "datasource",
"uid": "-- Mixed --"
},
"gridPos": {
"h": 4,
"w": 4,
"x": 16,
"y": 11
},
"id": 17,
"pluginVersion": "v10.4.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "$datasource"
},
"expr": "sum(elasticsearch_thread_pool_queue_count{cluster=~\"$cluster\",type!=\"management\"}) by (type)\n",
"legendFormat": "{{type}}"
}
],
"title": "Queue Count",
"type": "timeseries"
},
{
"collapsed": false,
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 15
},
"id": 18,
"panels": [ ],
"title": "Memory",
"type": "row"
},
{
"datasource": {
"type": "datasource",
"uid": "-- Mixed --"
},
"fieldConfig": {
"defaults": {
"unit": "bytes"
}
},
"gridPos": {
"h": 4,
"w": 6,
"x": 0,
"y": 16
},
"id": 19,
"pluginVersion": "v10.4.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "$datasource"
},
"expr": "elasticsearch_jvm_memory_used_bytes{cluster=~\"$cluster\"}\n",
"legendFormat": "{{name}} {{area}}"
}
],
"title": "Memory Usage",
"type": "timeseries"
},
{
"datasource": {
"type": "datasource",
"uid": "-- Mixed --"
},
"fieldConfig": {
"defaults": {
"max": 1,
"min": 0,
"unit": "percentunit"
}
},
"gridPos": {
"h": 4,
"w": 6,
"x": 6,
"y": 16
},
"id": 20,
"pluginVersion": "v10.4.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "$datasource"
},
"expr": "avg_over_time(\n elasticsearch_jvm_memory_used_bytes{cluster=~\"$cluster\"}[15m]\n) /\nelasticsearch_jvm_memory_max_bytes{cluster=~\"$cluster\"}\n",
"legendFormat": "{{name}} {{area}}"
}
],
"title": "Memory 15m Avg",
"type": "timeseries"
},
{
"datasource": {
"type": "datasource",
"uid": "-- Mixed --"
},
"fieldConfig": {
"defaults": {
"unit": "bytes"
}
},
"gridPos": {
"h": 4,
"w": 6,
"x": 12,
"y": 16
},
"id": 21,
"pluginVersion": "v10.4.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "$datasource"
},
"expr": "elasticsearch_jvm_memory_max_bytes{cluster=~\"$cluster\"}\n",
"legendFormat": "{{name}} {{area}}"
}
],
"title": "Memory Max",
"type": "timeseries"
},
{
"datasource": {
"type": "datasource",
"uid": "-- Mixed --"
},
"fieldConfig": {
"defaults": {
"unit": "s"
}
},
"gridPos": {
"h": 4,
"w": 6,
"x": 18,
"y": 16
},
"id": 22,
"pluginVersion": "v10.4.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "$datasource"
},
"expr": "rate(\n elasticsearch_jvm_gc_collection_seconds_sum{cluster=~\"$cluster\"}[$__rate_interval]\n)\n",
"legendFormat": "{{name}} {{gc}}"
}
],
"title": "GC Rate",
"type": "timeseries"
},
{
"collapsed": false,
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 20
},
"id": 23,
"panels": [ ],
"title": "Threads",
"type": "row"
},
{
"datasource": {
"type": "datasource",
"uid": "-- Mixed --"
},
"gridPos": {
"h": 4,
"w": 12,
"x": 0,
"y": 21
},
"id": 24,
"pluginVersion": "v10.4.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "$datasource"
},
"expr": "elasticsearch_thread_pool_active_count{cluster=~\"$cluster\"}\n",
"legendFormat": "{{type}}"
}
],
"title": "Thread Pools",
"type": "timeseries"
},
{
"datasource": {
"type": "datasource",
"uid": "-- Mixed --"
},
"gridPos": {
"h": 4,
"w": 12,
"x": 12,
"y": 21
},
"id": 25,
"pluginVersion": "v10.4.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "$datasource"
},
"expr": "elasticsearch_thread_pool_rejected_count{cluster=~\"$cluster\"}\n",
"legendFormat": "{{name}} {{type}}"
}
],
"title": "Thread Pool Rejections",
"type": "timeseries"
},
{
"collapsed": false,
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 25
},
"id": 26,
"panels": [ ],
"title": "Network",
"type": "row"
},
{
"datasource": {
"type": "datasource",
"uid": "-- Mixed --"
},
"fieldConfig": {
"defaults": {
"unit": "bytes"
}
},
"gridPos": {
"h": 4,
"w": 24,
"x": 0,
"y": 26
},
"id": 27,
"pluginVersion": "v10.4.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "$datasource"
},
"expr": "rate(\n elasticsearch_transport_rx_size_bytes_total{cluster=~\"$cluster\"}[$__rate_interval]\n)\n",
"legendFormat": "{{name}} TX"
},
{
"datasource": {
"type": "prometheus",
"uid": "$datasource"
},
"expr": "rate(\n elasticsearch_transport_tx_size_bytes_total{cluster=~\"$cluster\"}[$__rate_interval]\n)\n",
"legendFormat": "{{name}} RX"
}
],
"title": "Transport Rate",
"type": "timeseries"
}
],
"refresh": "1m",
"schemaVersion": 36,
"tags": [
"elasticsearch-exporter-mixin"
],
"templating": {
"list": [
{
"name": "datasource",
"query": "prometheus",
"type": "datasource"
},
{
"datasource": {
"type": "prometheus",
"uid": "${datasource}"
},
"name": "cluster",
"query": "label_values(elasticsearch_cluster_health_status, cluster)",
"type": "query"
}
]
},
"time": {
"from": "now-1h",
"to": "now"
},
"timezone": "utc",
"title": "Elasticsearch Exporter / Cluster"
}

View File

@ -0,0 +1 @@
{}

View File

@ -0,0 +1,6 @@
{
_config+:: {
dashboardNamePrefix: 'Elasticsearch Exporter / ',
dashboardTags: ['elasticsearch-exporter-mixin'],
},
}

View File

@ -0,0 +1,3 @@
local dashboards = (import 'mixin.libsonnet').grafanaDashboards;
{ [name]: dashboards[name] for name in std.objectFields(dashboards) }

View File

@ -0,0 +1,67 @@
local g = import 'g.libsonnet';
local dashboard = g.dashboard;
local row = g.panel.row;
local panels = import './panels.libsonnet';
local queries = import './queries.libsonnet';
local variables = import './variables.libsonnet';
local util = import './util.libsonnet';
{
grafanaDashboards+:: {
'cluster.json':
dashboard.new('%s Cluster' % $._config.dashboardNamePrefix)
+ dashboard.withTags($._config.dashboardTags)
+ dashboard.withRefresh('1m')
+ dashboard.time.withFrom(value='now-1h')
+ dashboard.graphTooltip.withSharedCrosshair()
+ dashboard.withVariables([
variables.datasource,
variables.cluster,
])
+ dashboard.withPanels(
util.makeGrid([
row.new('Overview')
+ row.withPanels([
panels.stat.nodes('Nodes', queries.runningNodes),
panels.stat.nodes('Data Nodes', queries.dataNodes),
panels.stat.nodes('Pending Tasks', queries.pendingTasks),
]),
row.new('Shards')
+ row.withPanels([
panels.stat.nodes('Active', queries.activeShards),
panels.stat.nodes('Active Primary', queries.activePrimaryShards),
panels.stat.nodes('Initializing', queries.initializingShards),
panels.stat.nodes('Relocating', queries.reloactingShards),
panels.stat.nodes('Unassigned', queries.unassignedShards),
panels.stat.nodes('DelayedUnassigned', queries.delayedUnassignedShards),
]),
row.new('Documents')
+ row.withPanels([
panels.timeSeries.base('Indexed Documents', queries.indexedDocuments),
panels.timeSeries.bytes('Index Size', queries.indexSize),
panels.timeSeries.base('Index Rate', queries.indexRate),
panels.timeSeries.base('Query Rate', queries.queryRate),
panels.timeSeries.base('Queue Count', queries.queueCount),
]),
row.new('Memory')
+ row.withPanels([
panels.timeSeries.bytes('Memory Usage', queries.memoryUsage),
panels.timeSeries.ratioMax1('Memory 15m Avg', queries.memoryUsageAverage15),
panels.timeSeries.bytes('Memory Max', queries.memoryMax),
panels.timeSeries.seconds('GC Rate', queries.gcSeconds),
]),
row.new('Threads')
+ row.withPanels([
panels.timeSeries.base('Thread Pools', queries.threadPoolActive),
panels.timeSeries.base('Thread Pool Rejections', queries.threadPoolRejections),
]),
row.new('Network')
+ row.withPanels([
panels.timeSeries.bytes('Transport Rate', [queries.transportTXRate, queries.transportRXRate]),
]),
]),
),
},
}

View File

@ -0,0 +1 @@
(import 'cluster.libsonnet')

View File

@ -0,0 +1 @@
import 'github.com/grafana/grafonnet/gen/grafonnet-latest/main.libsonnet'

View File

@ -0,0 +1,38 @@
local g = import 'g.libsonnet';
{
stat: {
local stat = g.panel.stat,
base(title, targets):
stat.new(title)
+ stat.queryOptions.withTargets(targets),
nodes: self.base,
},
timeSeries: {
local timeSeries = g.panel.timeSeries,
base(title, targets):
timeSeries.new(title)
+ timeSeries.queryOptions.withTargets(targets),
ratio(title, targets):
self.base(title, targets)
+ timeSeries.standardOptions.withUnit('percentunit'),
ratioMax1(title, targets):
self.ratio(title, targets)
+ timeSeries.standardOptions.withMax(1)
+ timeSeries.standardOptions.withMin(0),
bytes(title, targets):
self.base(title, targets)
+ timeSeries.standardOptions.withUnit('bytes'),
seconds(title, targets):
self.base(title, targets)
+ timeSeries.standardOptions.withUnit('s'),
},
}

View File

@ -0,0 +1,11 @@
local g = import './g.libsonnet';
local prometheusQuery = g.query.prometheus;
local variables = import './variables.libsonnet';
(import './queries/general.libsonnet') +
(import './queries/shard.libsonnet') +
(import './queries/document.libsonnet') +
(import './queries/memory.libsonnet') +
(import './queries/threads.libsonnet') +
(import './queries/network.libsonnet')

View File

@ -0,0 +1,50 @@
local g = import '../g.libsonnet';
local prometheusQuery = g.query.prometheus;
local variables = import '../variables.libsonnet';
{
indexedDocuments:
prometheusQuery.new(
'$' + variables.datasource.name,
|||
elasticsearch_indices_docs{cluster=~"$cluster"}
|||
),
indexSize:
prometheusQuery.new(
'$' + variables.datasource.name,
|||
elasticsearch_indices_store_size_bytes{cluster=~"$cluster"}
|||
),
indexRate:
prometheusQuery.new(
'$' + variables.datasource.name,
|||
rate(elasticsearch_indices_indexing_index_total{cluster=~"$cluster"}[$__rate_interval])
|||
)
+ prometheusQuery.withLegendFormat('{{name}}'),
queryRate:
prometheusQuery.new(
'$' + variables.datasource.name,
|||
rate(elasticsearch_indices_search_query_total{cluster=~"$cluster"}[$__rate_interval])
|||
)
+ prometheusQuery.withLegendFormat('{{name}}'),
queueCount:
prometheusQuery.new(
'$' + variables.datasource.name,
|||
sum(elasticsearch_thread_pool_queue_count{cluster=~"$cluster",type!="management"}) by (type)
|||
)
+ prometheusQuery.withLegendFormat('{{type}}'),
}

View File

@ -0,0 +1,35 @@
local g = import '../g.libsonnet';
local prometheusQuery = g.query.prometheus;
local variables = import '../variables.libsonnet';
{
runningNodes:
prometheusQuery.new(
'$' + variables.datasource.name,
|||
sum(
elasticsearch_cluster_health_number_of_nodes{cluster=~"$cluster"}
)
|||
),
dataNodes:
prometheusQuery.new(
'$' + variables.datasource.name,
|||
sum(
elasticsearch_cluster_health_number_of_data_nodes{cluster=~"$cluster"}
)
|||
),
pendingTasks:
prometheusQuery.new(
'$' + variables.datasource.name,
|||
sum(
elasticsearch_cluster_health_number_of_pending_tasks{cluster=~"$cluster"}
)
|||
),
}

View File

@ -0,0 +1,47 @@
local g = import '../g.libsonnet';
local prometheusQuery = g.query.prometheus;
local variables = import '../variables.libsonnet';
{
memoryUsage:
prometheusQuery.new(
'$' + variables.datasource.name,
|||
elasticsearch_jvm_memory_used_bytes{cluster=~"$cluster"}
|||
)
+ prometheusQuery.withLegendFormat('{{name}} {{area}}'),
memoryUsageAverage15:
prometheusQuery.new(
'$' + variables.datasource.name,
|||
avg_over_time(
elasticsearch_jvm_memory_used_bytes{cluster=~"$cluster"}[15m]
) /
elasticsearch_jvm_memory_max_bytes{cluster=~"$cluster"}
|||
)
+ prometheusQuery.withLegendFormat('{{name}} {{area}}'),
memoryMax:
prometheusQuery.new(
'$' + variables.datasource.name,
|||
elasticsearch_jvm_memory_max_bytes{cluster=~"$cluster"}
|||
)
+ prometheusQuery.withLegendFormat('{{name}} {{area}}'),
gcSeconds:
prometheusQuery.new(
'$' + variables.datasource.name,
|||
rate(
elasticsearch_jvm_gc_collection_seconds_sum{cluster=~"$cluster"}[$__rate_interval]
)
|||
)
+ prometheusQuery.withLegendFormat('{{name}} {{gc}}'),
}

View File

@ -0,0 +1,28 @@
local g = import '../g.libsonnet';
local prometheusQuery = g.query.prometheus;
local variables = import '../variables.libsonnet';
{
transportTXRate:
prometheusQuery.new(
'$' + variables.datasource.name,
|||
rate(
elasticsearch_transport_rx_size_bytes_total{cluster=~"$cluster"}[$__rate_interval]
)
|||
)
+ prometheusQuery.withLegendFormat('{{name}} TX'),
transportRXRate:
prometheusQuery.new(
'$' + variables.datasource.name,
|||
rate(
elasticsearch_transport_tx_size_bytes_total{cluster=~"$cluster"}[$__rate_interval]
)
|||
)
+ prometheusQuery.withLegendFormat('{{name}} RX'),
}

View File

@ -0,0 +1,66 @@
local g = import '../g.libsonnet';
local prometheusQuery = g.query.prometheus;
local variables = import '../variables.libsonnet';
{
activeShards:
prometheusQuery.new(
'$' + variables.datasource.name,
|||
sum(
elasticsearch_cluster_health_active_shards{cluster=~"$cluster"}
)
|||
),
activePrimaryShards:
prometheusQuery.new(
'$' + variables.datasource.name,
|||
sum(
elasticsearch_cluster_health_active_primary_shards{cluster=~"$cluster"}
)
|||
),
initializingShards:
prometheusQuery.new(
'$' + variables.datasource.name,
|||
sum(
elasticsearch_cluster_health_initializing_shards{cluster=~"$cluster"}
)
|||
),
reloactingShards:
prometheusQuery.new(
'$' + variables.datasource.name,
|||
sum(
elasticsearch_cluster_health_reloacting_shards{cluster=~"$cluster"}
)
|||
),
unassignedShards:
prometheusQuery.new(
'$' + variables.datasource.name,
|||
sum(
elasticsearch_cluster_health_unassigned_shards{cluster=~"$cluster"}
)
|||
),
delayedUnassignedShards:
prometheusQuery.new(
'$' + variables.datasource.name,
|||
sum(
elasticsearch_cluster_health_delayed_unassigned_shards{cluster=~"$cluster"}
)
|||
),
}

View File

@ -0,0 +1,24 @@
local g = import '../g.libsonnet';
local prometheusQuery = g.query.prometheus;
local variables = import '../variables.libsonnet';
{
threadPoolActive:
prometheusQuery.new(
'$' + variables.datasource.name,
|||
elasticsearch_thread_pool_active_count{cluster=~"$cluster"}
|||
)
+ prometheusQuery.withLegendFormat('{{type}}'),
threadPoolRejections:
prometheusQuery.new(
'$' + variables.datasource.name,
|||
elasticsearch_thread_pool_rejected_count{cluster=~"$cluster"}
|||
)
+ prometheusQuery.withLegendFormat('{{name}} {{type}}'),
}

View File

@ -0,0 +1,66 @@
local g = import 'g.libsonnet';
local panelUtil = g.util.panel;
{
local gridWidth = 24,
// makeGrid returns an array of panels organized into a grid layout.
// This is a modified version of the grafonnet makeGrid function to
// calculate the width of each panel based on the number of panels.
makeGrid(panels, panelHeight=4, startY=0):
local sanitizePanels(ps) =
// Figure out the number of panels and the width of each panel
local numPanels = std.length(ps);
local panelWidth = std.floor(gridWidth / numPanels);
// Sanitize the panels, this ensures tht the panels have the valid gridPos
std.map(
function(p)
local sanePanel = panelUtil.sanitizePanel(p, defaultHeight=panelHeight);
(
if p.type == 'row'
then sanePanel {
panels: sanitizePanels(sanePanel.panels),
}
else sanePanel {
gridPos+: {
w: panelWidth,
},
}
),
ps
);
local sanitizedPanels = sanitizePanels(panels);
local grouped = panelUtil.groupPanelsInRows(sanitizedPanels);
local panelsBeforeRows = panelUtil.getPanelsBeforeNextRow(grouped);
local rowPanels =
std.filter(
function(p) p.type == 'row',
grouped
);
local CalculateXforPanel(index, panel) =
local panelsPerRow = std.floor(gridWidth / panel.gridPos.w);
local col = std.mod(index, panelsPerRow);
panel { gridPos+: { x: panel.gridPos.w * col } };
local panelsBeforeRowsWithX = std.mapWithIndex(CalculateXforPanel, panelsBeforeRows);
local rowPanelsWithX =
std.map(
function(row)
row { panels: std.mapWithIndex(CalculateXforPanel, row.panels) },
rowPanels
);
local uncollapsed = panelUtil.resolveCollapsedFlagOnRows(panelsBeforeRowsWithX + rowPanelsWithX);
local normalized = panelUtil.normalizeY(uncollapsed);
std.map(function(p) p { gridPos+: { y+: startY } }, normalized),
}

View File

@ -0,0 +1,15 @@
local g = import './g.libsonnet';
local var = g.dashboard.variable;
{
datasource:
var.datasource.new('datasource', 'prometheus'),
cluster:
var.query.new('cluster')
+ var.query.withDatasourceFromVariable(self.datasource)
+ var.query.queryTypes.withLabelValues(
'cluster',
'elasticsearch_cluster_health_status',
),
}

View File

@ -0,0 +1,15 @@
{
"version": 1,
"dependencies": [
{
"source": {
"git": {
"remote": "https://github.com/grafana/grafonnet.git",
"subdir": "gen/grafonnet-latest"
}
},
"version": "main"
}
],
"legacyImports": true
}

View File

@ -0,0 +1,46 @@
{
"version": 1,
"dependencies": [
{
"source": {
"git": {
"remote": "https://github.com/grafana/grafonnet.git",
"subdir": "gen/grafonnet-latest"
}
},
"version": "1c56af39815c4903e47c27194444456f005f65df",
"sum": "GxEO83uxgsDclLp/fmlUJZDbSGpeUZY6Ap3G2cgdL1g="
},
{
"source": {
"git": {
"remote": "https://github.com/grafana/grafonnet.git",
"subdir": "gen/grafonnet-v10.4.0"
}
},
"version": "1c56af39815c4903e47c27194444456f005f65df",
"sum": "DKj+Sn+rlI48g/aoJpzkfPge46ya0jLk5kcZoiZ2X/I="
},
{
"source": {
"git": {
"remote": "https://github.com/jsonnet-libs/docsonnet.git",
"subdir": "doc-util"
}
},
"version": "6ac6c69685b8c29c54515448eaca583da2d88150",
"sum": "BrAL/k23jq+xy9oA7TWIhUx07dsA/QLm3g7ktCwe//U="
},
{
"source": {
"git": {
"remote": "https://github.com/jsonnet-libs/xtd.git",
"subdir": ""
}
},
"version": "63d430b69a95741061c2f7fc9d84b1a778511d9c",
"sum": "qiZi3axUSXCVzKUF83zSAxklwrnitMmrDK4XAfjPMdE="
}
],
"legacyImports": false
}

View File

@ -0,0 +1,3 @@
// (import 'alerts/alerts.libsonnet') +
(import 'dashboards/dashboards.libsonnet') +
(import 'config.libsonnet')

55
examples/auth_modules.yml Normal file
View File

@ -0,0 +1,55 @@
# Example exporter-config.yml demonstrating multiple auth modules
# Each module can be referenced with ?auth_module=<name> in /probe requests.
auth_modules:
###########################################################################
# 1. Simple basic-auth over HTTPS #
###########################################################################
prod_basic:
type: userpass
userpass:
username: metrics
password: s3cr3t
# extra URL query parameters are appended to the target DSN
options:
sslmode: disable # becomes ?sslmode=disable
###########################################################################
# 2. Read-only account for staging cluster #
###########################################################################
staging_ro:
type: userpass
userpass:
username: readonly
password: changeme
###########################################################################
# 3. API-Key authentication #
###########################################################################
prod_key:
type: apikey
apikey: BASE64-ENCODED-KEY==
###########################################################################
# 5. AWS SigV4 signing with optional TLS settings #
###########################################################################
aws_sigv4:
type: aws
aws:
region: us-east-1
# role_arn is optional
# Optional TLS configuration for transport security
tls:
ca_file: /etc/ssl/ca.pem
insecure_skip_verify: false
###########################################################################
# 6. Client certificate authentication only (no username/password) #
###########################################################################
pki_mtls:
type: tls # This auth type uses ONLY client certificates for authentication
tls:
ca_file: /etc/ssl/pki/ca.pem # Optional: CA for server verification
cert_file: /etc/ssl/pki/client.pem # Required: Client certificate for auth
key_file: /etc/ssl/pki/client-key.pem # Required: Client private key for auth
insecure_skip_verify: false # Optional: Skip server cert validation

View File

@ -0,0 +1,33 @@
scrape_configs:
- job_name: es-multi
metrics_path: /probe
# Default parameters for all scrapes in this job.
# Can be overridden by labels on a per-target basis.
params:
auth_module: [prod_key]
static_configs:
# This is a target group. All targets here will use the default 'prod_key' auth_module.
- targets:
- https://es-prod-1:9200
- https://es-prod-2:9200
# This is another target group.
- targets:
- https://es-stage:9200
# The __param_ prefix on a label causes it to be added as a URL parameter.
# This will override the default auth_module for this target.
labels:
__param_auth_module: staging_basic
relabel_configs:
# The following relabeling rules are applied to every target.
# 1. The special label __address__ (the target address) is saved as the 'target' URL parameter.
- source_labels: [__address__]
target_label: __param_target
# 2. The 'target' parameter is used as the 'instance' label for the scraped metrics.
- source_labels: [__param_target]
target_label: instance
# 3. The scrape address is rewritten to point to the exporter.
- target_label: __address__
replacement: exporter:9114 # host:port of the single exporter

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,111 @@
{
"status": "green",
"cluster_name": "docker-cluster",
"indicators": {
"master_is_stable": {
"status": "green",
"symptom": "The cluster has a stable master node",
"details": {
"current_master": {
"node_id": "X8BAj1mfQ3qgcSoAlG3HHw",
"name": "5da1610e99a7"
},
"recent_masters": [
{
"node_id": "X8BAj1mfQ3qgcSoAlG3HHw",
"name": "5da1610e99a7"
}
]
}
},
"repository_integrity": {
"status": "green",
"symptom": "All repositories are healthy.",
"details": {
"total_repositories": 1
}
},
"shards_capacity": {
"status": "green",
"symptom": "The cluster has enough room to add new shards.",
"details": {
"data": {
"max_shards_in_cluster": 13500
},
"frozen": {
"max_shards_in_cluster": 9000
}
}
},
"shards_availability": {
"status": "green",
"symptom": "This cluster has all shards available.",
"details": {
"restarting_replicas": 0,
"creating_primaries": 0,
"initializing_replicas": 0,
"unassigned_replicas": 0,
"started_primaries": 11703,
"restarting_primaries": 0,
"initializing_primaries": 0,
"creating_replicas": 0,
"started_replicas": 1701,
"unassigned_primaries": 0
},
"impacts": [
{
"id": "elasticsearch:health:shards_availability:impact:replica_unassigned",
"severity": 2,
"description": "Searches might be slower than usual. Fewer redundant copies of the data exist on 1 index [twitter].",
"impact_areas": [
"search"
]
}
],
"diagnosis": [
{
"id": "elasticsearch:health:shards_availability:diagnosis:increase_tier_capacity_for_allocations:tier:data_content",
"cause": "Elasticsearch isn't allowed to allocate some shards from these indices to any of the nodes in the desired data tier because there are not enough nodes in the [data_content] tier to allocate each shard copy on a different node.",
"action": "Increase the number of nodes in this tier or decrease the number of replica shards in the affected indices.",
"help_url": "https://ela.st/tier-capacity",
"affected_resources": {
"indices": [
"twitter"
]
}
}
]
},
"disk": {
"status": "green",
"symptom": "The cluster has enough available disk space.",
"details": {
"indices_with_readonly_block": 0,
"nodes_with_enough_disk_space": 1,
"nodes_with_unknown_disk_status": 0,
"nodes_over_high_watermark": 0,
"nodes_over_flood_stage_watermark": 0
}
},
"data_stream_lifecycle": {
"status": "green",
"symptom": "No data stream lifecycle health data available yet. Health information will be reported after the first run."
},
"ilm": {
"status": "green",
"symptom": "Index Lifecycle Management is running",
"details": {
"policies": 17,
"ilm_status": "RUNNING"
}
},
"slm": {
"status": "green",
"symptom": "No Snapshot Lifecycle Management policies configured",
"details": {
"slm_status": "RUNNING",
"policies": 0
}
}
}
}

681
fixtures/indices/1.7.6.json Normal file
View File

@ -0,0 +1,681 @@
{
"_shards": {
"total": 20,
"successful": 10,
"failed": 0
},
"_all": {
"primaries": {
"docs": {
"count": 5,
"deleted": 0
},
"store": {
"size_in_bytes": 13798,
"throttle_time_in_millis": 0
},
"indexing": {
"index_total": 5,
"index_time_in_millis": 52,
"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": 5,
"total_time_in_millis": 163
},
"flush": {
"total": 0,
"total_time_in_millis": 0
},
"warmer": {
"current": 0,
"total": 30,
"total_time_in_millis": 42
},
"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": 5,
"memory_in_bytes": 18410,
"index_writer_memory_in_bytes": 0,
"index_writer_max_memory_in_bytes": 671088640,
"version_map_memory_in_bytes": 0,
"fixed_bit_set_memory_in_bytes": 0
},
"translog": {
"operations": 5,
"size_in_bytes": 102
},
"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": 5,
"deleted": 0
},
"store": {
"size_in_bytes": 13798,
"throttle_time_in_millis": 0
},
"indexing": {
"index_total": 5,
"index_time_in_millis": 52,
"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": 5,
"total_time_in_millis": 163
},
"flush": {
"total": 0,
"total_time_in_millis": 0
},
"warmer": {
"current": 0,
"total": 30,
"total_time_in_millis": 42
},
"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": 5,
"memory_in_bytes": 18410,
"index_writer_memory_in_bytes": 0,
"index_writer_max_memory_in_bytes": 671088640,
"version_map_memory_in_bytes": 0,
"fixed_bit_set_memory_in_bytes": 0
},
"translog": {
"operations": 5,
"size_in_bytes": 102
},
"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": 3,
"deleted": 0
},
"store": {
"size_in_bytes": 8207,
"throttle_time_in_millis": 0
},
"indexing": {
"index_total": 3,
"index_time_in_millis": 6,
"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": 38
},
"flush": {
"total": 0,
"total_time_in_millis": 0
},
"warmer": {
"current": 0,
"total": 16,
"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": 3,
"memory_in_bytes": 11046,
"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": 3,
"size_in_bytes": 102
},
"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": 8207,
"throttle_time_in_millis": 0
},
"indexing": {
"index_total": 3,
"index_time_in_millis": 6,
"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": 38
},
"flush": {
"total": 0,
"total_time_in_millis": 0
},
"warmer": {
"current": 0,
"total": 16,
"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": 3,
"memory_in_bytes": 11046,
"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": 3,
"size_in_bytes": 102
},
"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": 2,
"deleted": 0
},
"store": {
"size_in_bytes": 5591,
"throttle_time_in_millis": 0
},
"indexing": {
"index_total": 2,
"index_time_in_millis": 46,
"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": 2,
"total_time_in_millis": 125
},
"flush": {
"total": 0,
"total_time_in_millis": 0
},
"warmer": {
"current": 0,
"total": 14,
"total_time_in_millis": 42
},
"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": 2,
"memory_in_bytes": 7364,
"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": 2,
"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": 2,
"deleted": 0
},
"store": {
"size_in_bytes": 5591,
"throttle_time_in_millis": 0
},
"indexing": {
"index_total": 2,
"index_time_in_millis": 46,
"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": 2,
"total_time_in_millis": 125
},
"flush": {
"total": 0,
"total_time_in_millis": 0
},
"warmer": {
"current": 0,
"total": 14,
"total_time_in_millis": 42
},
"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": 2,
"memory_in_bytes": 7364,
"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": 2,
"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
}
}
}
}
}

765
fixtures/indices/2.4.5.json Normal file
View File

@ -0,0 +1,765 @@
{
"_shards": {
"total": 20,
"successful": 10,
"failed": 0
},
"_all": {
"primaries": {
"docs": {
"count": 5,
"deleted": 0
},
"store": {
"size_in_bytes": 3610,
"throttle_time_in_millis": 0
},
"indexing": {
"index_total": 5,
"index_time_in_millis": 40,
"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": 209715200
},
"refresh": {
"total": 5,
"total_time_in_millis": 171
},
"flush": {
"total": 0,
"total_time_in_millis": 0
},
"warmer": {
"current": 0,
"total": 30,
"total_time_in_millis": 12
},
"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": 5,
"memory_in_bytes": 10530,
"terms_memory_in_bytes": 7550,
"stored_fields_memory_in_bytes": 1560,
"term_vectors_memory_in_bytes": 0,
"norms_memory_in_bytes": 960,
"doc_values_memory_in_bytes": 460,
"index_writer_memory_in_bytes": 0,
"index_writer_max_memory_in_bytes": 103887660,
"version_map_memory_in_bytes": 0,
"fixed_bit_set_memory_in_bytes": 0
},
"translog": {
"operations": 5,
"size_in_bytes": 843
},
"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": 5,
"deleted": 0
},
"store": {
"size_in_bytes": 3610,
"throttle_time_in_millis": 0
},
"indexing": {
"index_total": 5,
"index_time_in_millis": 40,
"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": 209715200
},
"refresh": {
"total": 5,
"total_time_in_millis": 171
},
"flush": {
"total": 0,
"total_time_in_millis": 0
},
"warmer": {
"current": 0,
"total": 30,
"total_time_in_millis": 12
},
"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": 5,
"memory_in_bytes": 10530,
"terms_memory_in_bytes": 7550,
"stored_fields_memory_in_bytes": 1560,
"term_vectors_memory_in_bytes": 0,
"norms_memory_in_bytes": 960,
"doc_values_memory_in_bytes": 460,
"index_writer_memory_in_bytes": 0,
"index_writer_max_memory_in_bytes": 103887660,
"version_map_memory_in_bytes": 0,
"fixed_bit_set_memory_in_bytes": 0
},
"translog": {
"operations": 5,
"size_in_bytes": 843
},
"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": 3,
"deleted": 0
},
"store": {
"size_in_bytes": 3350,
"throttle_time_in_millis": 0
},
"indexing": {
"index_total": 3,
"index_time_in_millis": 6,
"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": 3,
"total_time_in_millis": 34
},
"flush": {
"total": 0,
"total_time_in_millis": 0
},
"warmer": {
"current": 0,
"total": 16,
"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": 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": 51943830,
"version_map_memory_in_bytes": 0,
"fixed_bit_set_memory_in_bytes": 0
},
"translog": {
"operations": 3,
"size_in_bytes": 470
},
"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": 3350,
"throttle_time_in_millis": 0
},
"indexing": {
"index_total": 3,
"index_time_in_millis": 6,
"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": 3,
"total_time_in_millis": 34
},
"flush": {
"total": 0,
"total_time_in_millis": 0
},
"warmer": {
"current": 0,
"total": 16,
"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": 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": 51943830,
"version_map_memory_in_bytes": 0,
"fixed_bit_set_memory_in_bytes": 0
},
"translog": {
"operations": 3,
"size_in_bytes": 470
},
"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": 2,
"deleted": 0
},
"store": {
"size_in_bytes": 260,
"throttle_time_in_millis": 0
},
"indexing": {
"index_total": 2,
"index_time_in_millis": 34,
"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": 2,
"total_time_in_millis": 137
},
"flush": {
"total": 0,
"total_time_in_millis": 0
},
"warmer": {
"current": 0,
"total": 14,
"total_time_in_millis": 12
},
"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": 2,
"memory_in_bytes": 4212,
"terms_memory_in_bytes": 3020,
"stored_fields_memory_in_bytes": 624,
"term_vectors_memory_in_bytes": 0,
"norms_memory_in_bytes": 384,
"doc_values_memory_in_bytes": 184,
"index_writer_memory_in_bytes": 0,
"index_writer_max_memory_in_bytes": 51943830,
"version_map_memory_in_bytes": 0,
"fixed_bit_set_memory_in_bytes": 0
},
"translog": {
"operations": 2,
"size_in_bytes": 373
},
"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": 2,
"deleted": 0
},
"store": {
"size_in_bytes": 260,
"throttle_time_in_millis": 0
},
"indexing": {
"index_total": 2,
"index_time_in_millis": 34,
"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": 2,
"total_time_in_millis": 137
},
"flush": {
"total": 0,
"total_time_in_millis": 0
},
"warmer": {
"current": 0,
"total": 14,
"total_time_in_millis": 12
},
"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": 2,
"memory_in_bytes": 4212,
"terms_memory_in_bytes": 3020,
"stored_fields_memory_in_bytes": 624,
"term_vectors_memory_in_bytes": 0,
"norms_memory_in_bytes": 384,
"doc_values_memory_in_bytes": 184,
"index_writer_memory_in_bytes": 0,
"index_writer_max_memory_in_bytes": 51943830,
"version_map_memory_in_bytes": 0,
"fixed_bit_set_memory_in_bytes": 0
},
"translog": {
"operations": 2,
"size_in_bytes": 373
},
"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
}
}
}
}
}

1437
fixtures/indices/5.4.2.json Normal file

File diff suppressed because it is too large Load Diff

1303
fixtures/indices/7.17.3.json Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,20 @@
{
"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": {}
}
}
}

View File

@ -0,0 +1,20 @@
{
"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": {}
}
}
}

View File

@ -0,0 +1,20 @@
{
"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": {}
}
}
}

View File

@ -0,0 +1,20 @@
{
"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": {}
}
}
}

View File

View File

View File

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,69 @@
{
"viber": {
"settings": {
"index": {
"creation_date": "1618593207186",
"number_of_shards": "5",
"number_of_replicas": "1",
"uuid": "lWg86KTARzO3r7lELytT1Q",
"version": {
"created": "6050499"
},
"provided_name": "viber"
}
}
},
"instagram": {
"settings": {
"index": {
"mapping": {
"total_fields": {
"limit": "10000"
}
},
"number_of_shards": "5",
"blocks": {
"read_only_allow_delete": "true"
},
"provided_name": "instagram",
"creation_date": "1618593203353",
"number_of_replicas": "1",
"uuid": "msb6eG7aT8GmNe-a4oyVtQ",
"version": {
"created": "6050499"
}
}
}
},
"twitter": {
"settings": {
"index": {
"number_of_shards": "5",
"blocks": {
"read_only_allow_delete": "true"
},
"provided_name": "twitter",
"creation_date": "1618593193641",
"number_of_replicas": "1",
"uuid": "YRUT8t4aSkKsNmGl7K3y4Q",
"version": {
"created": "6050499"
}
}
}
},
"facebook": {
"settings": {
"index": {
"creation_date": "1618593199101",
"number_of_shards": "5",
"number_of_replicas": "1",
"uuid": "trZhb_YOTV-RWKitTYw81A",
"version": {
"created": "6050499"
},
"provided_name": "facebook"
}
}
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More