diff --git a/collector/indices_mappings.go b/collector/indices_mappings.go index bfe072ab..5f49eceb 100644 --- a/collector/indices_mappings.go +++ b/collector/indices_mappings.go @@ -42,9 +42,6 @@ type IndicesMappings struct { client *http.Client url *url.URL - up prometheus.Gauge - totalScrapes, jsonParseFailures prometheus.Counter - metrics []*indicesMappingsMetric } @@ -57,18 +54,6 @@ func NewIndicesMappings(logger log.Logger, client *http.Client, url *url.URL) *I client: client, url: url, - up: prometheus.NewGauge(prometheus.GaugeOpts{ - Name: prometheus.BuildFQName(namespace, subsystem, "up"), - Help: "Was the last scrape of the Elasticsearch Indices Mappings endpoint successful.", - }), - totalScrapes: prometheus.NewCounter(prometheus.CounterOpts{ - Name: prometheus.BuildFQName(namespace, subsystem, "scrapes_total"), - Help: "Current total Elasticsearch Indices Mappings scrapes.", - }), - jsonParseFailures: prometheus.NewCounter(prometheus.CounterOpts{ - Name: prometheus.BuildFQName(namespace, subsystem, "json_parse_failures_total"), - Help: "Number of errors while parsing JSON.", - }), metrics: []*indicesMappingsMetric{ { Type: prometheus.GaugeValue, @@ -117,10 +102,6 @@ func (im *IndicesMappings) Describe(ch chan<- *prometheus.Desc) { for _, metric := range im.metrics { ch <- metric.Desc } - - ch <- im.up.Desc() - ch <- im.totalScrapes.Desc() - ch <- im.jsonParseFailures.Desc() } func (im *IndicesMappings) getAndParseURL(u *url.URL) (*IndicesMappingsResponse, error) { @@ -148,7 +129,6 @@ func (im *IndicesMappings) getAndParseURL(u *url.URL) (*IndicesMappingsResponse, var imr IndicesMappingsResponse if err := json.Unmarshal(body, &imr); err != nil { - im.jsonParseFailures.Inc() return nil, err } @@ -163,24 +143,14 @@ func (im *IndicesMappings) fetchAndDecodeIndicesMappings() (*IndicesMappingsResp // Collect gets all indices mappings metric values func (im *IndicesMappings) Collect(ch chan<- prometheus.Metric) { - - im.totalScrapes.Inc() - defer func() { - ch <- im.up - ch <- im.totalScrapes - ch <- im.jsonParseFailures - }() - indicesMappingsResponse, err := im.fetchAndDecodeIndicesMappings() if err != nil { - im.up.Set(0) level.Warn(im.logger).Log( "msg", "failed to fetch and decode cluster mappings stats", "err", err, ) return } - im.up.Set(1) for _, metric := range im.metrics { for indexName, mappings := range *indicesMappingsResponse { diff --git a/collector/indices_mappings_test.go b/collector/indices_mappings_test.go index 7031ada2..65c61ffe 100644 --- a/collector/indices_mappings_test.go +++ b/collector/indices_mappings_test.go @@ -14,13 +14,16 @@ package collector import ( - "fmt" + "io" "net/http" "net/http/httptest" "net/url" + "os" + "strings" "testing" "github.com/go-kit/log" + "github.com/prometheus/client_golang/prometheus/testutil" ) func TestMapping(t *testing.T) { @@ -66,315 +69,58 @@ func TestMapping(t *testing.T) { } }'*/ // curl http://localhost:9200/_all/_mapping - tcs := map[string]string{ - "7.8.0": `{ - "facebook": { - "mappings": { - "properties": { - "contact": { - "properties": { - "email": { - "type": "text", - "fields": { - "raw": { - "type": "keyword" - } - } - }, - "phone": { - "type": "text" - } - } - }, - "name": { - "type": "text", - "fields": { - "raw": { - "type": "keyword" - } - } - } - } - } - }, - "twitter": { - "mappings": { - "properties": { - "email": { - "type": "keyword" - }, - "phone": { - "type": "keyword" - } - } - } - } - }`, + tests := []struct { + name string + file string + want string + }{ + { + name: "7.8.0", + file: "../fixtures/indices_mappings/7.8.0.json", + want: ` +# HELP elasticsearch_indices_mappings_stats_fields Current number fields within cluster. +# TYPE elasticsearch_indices_mappings_stats_fields gauge +elasticsearch_indices_mappings_stats_fields{index="facebook"} 6 +elasticsearch_indices_mappings_stats_fields{index="twitter"} 2 + `, + }, + { + name: "counts", + file: "../fixtures/indices_mappings/counts.json", + want: ` +# HELP elasticsearch_indices_mappings_stats_fields Current number fields within cluster. +# TYPE elasticsearch_indices_mappings_stats_fields gauge +elasticsearch_indices_mappings_stats_fields{index="test-data-2023.01.20"} 40 + `, + }, } - 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) - defer ts.Close() - u, err := url.Parse(ts.URL) - if err != nil { - t.Fatalf("Failed to parse URL: %s", err) - } - c := NewIndicesMappings(log.NewNopLogger(), http.DefaultClient, u) - imr, err := c.fetchAndDecodeIndicesMappings() + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + f, err := os.Open(tt.file) if err != nil { - t.Fatalf("Failed to fetch or decode indices mappings: %s", err) - } - t.Logf("[%s/%s] All Indices Mappings Response: %+v", hn, ver, imr) - - response := *imr - if *response["facebook"].Mappings.Properties["contact"].Properties["phone"].Type != "text" { - t.Errorf("Marshalling error at facebook.contact.phone") + t.Fatal(err) } + defer f.Close() - if *response["facebook"].Mappings.Properties["contact"].Properties["email"].Fields["raw"].Type != "keyword" { - t.Errorf("Marshalling error at facebook.contact.email.raw") - } - - if *response["facebook"].Mappings.Properties["name"].Type != "text" { - t.Errorf("Marshalling error at facebook.name") - } - - if *response["facebook"].Mappings.Properties["name"].Fields["raw"].Type != "keyword" { - t.Errorf("Marshalling error at facebook.name.raw") - } + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + io.Copy(w, f) + })) + defer ts.Close() - if *response["twitter"].Mappings.Properties["email"].Type != "keyword" { - t.Errorf("Marshalling error at twitter.email") + u, err := url.Parse(ts.URL) + if err != nil { + t.Fatal(err) } - if *response["twitter"].Mappings.Properties["phone"].Type != "keyword" { - t.Errorf("Marshalling error at twitter.phone") + c := NewIndicesMappings(log.NewNopLogger(), http.DefaultClient, u) + if err != nil { + t.Fatal(err) } - } - } -} - -func TestIndexMappingFieldCount(t *testing.T) { - - testIndexNumFields := 40.0 - testIndexName := "test-data-2023.01.20" - - rawMapping := `{ - "test-data-2023.01.20": { - "mappings": { - "properties": { - "data": { - "type": "object", - "properties": { - "field1": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword", - "ignore_above": 256 - } - } - }, - "field10": { - "type": "long" - }, - "field2": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword", - "ignore_above": 256 - } - } - }, - "field3": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword", - "ignore_above": 256 - } - } - }, - "field4": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword", - "ignore_above": 256 - } - } - }, - "field5": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword", - "ignore_above": 256 - } - } - }, - "field6": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword", - "ignore_above": 256 - } - } - }, - "field7": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword", - "ignore_above": 256 - } - } - }, - "field8": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword", - "ignore_above": 256 - } - } - }, - "field9": { - "type": "long" - } - } - }, - "data2": { - "properties": { - "field1": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword", - "ignore_above": 256 - } - } - }, - "field2": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword", - "ignore_above": 256 - } - } - }, - "field3": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword", - "ignore_above": 256 - } - } - }, - "field4": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword", - "ignore_above": 256 - } - } - }, - "field5": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword", - "ignore_above": 256 - } - } - }, - "nested_field6": { - "properties": { - "field1": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword", - "ignore_above": 256 - } - } - }, - "field2": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword", - "ignore_above": 256 - } - } - }, - "field3": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword", - "ignore_above": 256 - } - } - }, - "field4": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword", - "ignore_above": 256 - } - } - }, - "field5": { - "type": "long" - } - } - } - } - } - } - } + if err := testutil.CollectAndCompare(c, strings.NewReader(tt.want)); err != nil { + t.Fatal(err) } - }` - - for _, handler := range map[string]http.Handler{ - "plain": http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - fmt.Fprintln(w, rawMapping) - }), - } { - - ts := httptest.NewServer(handler) - defer ts.Close() - - u, err := url.Parse(ts.URL) - if err != nil { - t.Fatalf("Failed to parse URL: %s", err) - } - c := NewIndicesMappings(log.NewNopLogger(), http.DefaultClient, u) - indicesMappingsResponse, err := c.fetchAndDecodeIndicesMappings() - if err != nil { - t.Fatalf("Failed to fetch or decode indices mappings: %s", err) - } - - response := *indicesMappingsResponse - mapping := response[testIndexName] - totalFields := countFieldsRecursive(mapping.Mappings.Properties, 0) - if totalFields != testIndexNumFields { - t.Errorf("Number of actual fields in index doesn't match the count returned by the recursive countFieldsRecursive function") - } - + }) } - } diff --git a/fixtures/indices_mappings/7.8.0.json b/fixtures/indices_mappings/7.8.0.json new file mode 100644 index 00000000..eb96f35b --- /dev/null +++ b/fixtures/indices_mappings/7.8.0.json @@ -0,0 +1,43 @@ +{ + "facebook": { + "mappings": { + "properties": { + "contact": { + "properties": { + "email": { + "type": "text", + "fields": { + "raw": { + "type": "keyword" + } + } + }, + "phone": { + "type": "text" + } + } + }, + "name": { + "type": "text", + "fields": { + "raw": { + "type": "keyword" + } + } + } + } + } + }, + "twitter": { + "mappings": { + "properties": { + "email": { + "type": "keyword" + }, + "phone": { + "type": "keyword" + } + } + } + } +} diff --git a/fixtures/indices_mappings/counts.json b/fixtures/indices_mappings/counts.json new file mode 100644 index 00000000..4550a79f --- /dev/null +++ b/fixtures/indices_mappings/counts.json @@ -0,0 +1,183 @@ +{ + "test-data-2023.01.20": { + "mappings": { + "properties": { + "data": { + "type": "object", + "properties": { + "field1": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "field10": { + "type": "long" + }, + "field2": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "field3": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "field4": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "field5": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "field6": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "field7": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "field8": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "field9": { + "type": "long" + } + } + }, + "data2": { + "properties": { + "field1": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "field2": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "field3": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "field4": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "field5": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "nested_field6": { + "properties": { + "field1": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "field2": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "field3": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "field4": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "field5": { + "type": "long" + } + } + } + } + } + } + } + } +}