Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 8 additions & 31 deletions collector/indices_settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,9 @@ type IndicesSettings struct {
client *http.Client
url *url.URL

up prometheus.Gauge
readOnlyIndices prometheus.Gauge

totalScrapes, jsonParseFailures prometheus.Counter
metrics []*indicesSettingsMetric
metrics []*indicesSettingsMetric
}

var (
Expand All @@ -58,22 +56,11 @@ func NewIndicesSettings(logger *slog.Logger, client *http.Client, url *url.URL)
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,
Expand Down Expand Up @@ -126,10 +113,11 @@ func NewIndicesSettings(logger *slog.Logger, client *http.Client, url *url.URL)

// 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 {
Expand All @@ -155,12 +143,10 @@ 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
Expand All @@ -181,26 +167,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)
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 {
Expand All @@ -217,4 +192,6 @@ func (cs *IndicesSettings) Collect(ch chan<- prometheus.Metric) {
}
}
cs.readOnlyIndices.Set(float64(c))

ch <- cs.readOnlyIndices
}
94 changes: 55 additions & 39 deletions collector/indices_settings_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,16 @@
package collector

import (
"fmt"
"io"
"net/http"
"net/http/httptest"
"net/url"
"os"
"path"
"strings"
"testing"

"github.com/prometheus/client_golang/prometheus/testutil"
"github.com/prometheus/common/promslog"
)

Expand Down Expand Up @@ -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(promslog.NewNopLogger(), http.DefaultClient, u)
nsr, err := c.fetchAndDecodeIndicesSettings()
if err != nil {
t.Fatalf("Failed to fetch or decode indices settings: %s", 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")
}
}
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"))

if err := testutil.CollectAndCompare(c, strings.NewReader(tt.want)); err != nil {
t.Fatal(err)
}
}
})
}
}
69 changes: 69 additions & 0 deletions fixtures/indices_settings/6.5.4.json
Original file line number Diff line number Diff line change
@@ -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"
}
}
}
}
Loading