diff --git a/inputs/elasticsearch/collector/nodes.go b/inputs/elasticsearch/collector/nodes.go index 4a5cb3afd..90dc14cd9 100644 --- a/inputs/elasticsearch/collector/nodes.go +++ b/inputs/elasticsearch/collector/nodes.go @@ -197,7 +197,7 @@ type Nodes struct { } // NewNodes defines Nodes Prometheus metrics -func NewNodes(client *http.Client, url *url.URL, all bool, node string, local bool, nodeStats []string) *Nodes { +func NewNodes(client *http.Client, url *url.URL, all bool, node string, local bool, nodeStats []string, clusterName string) *Nodes { return &Nodes{ client: client, url: url, @@ -209,14 +209,26 @@ func NewNodes(client *http.Client, url *url.URL, all bool, node string, local bo up: prometheus.NewGauge(prometheus.GaugeOpts{ Name: prometheus.BuildFQName(namespace, "node_stats", "up"), Help: "Was the last scrape of the Elasticsearch nodes endpoint successful.", + ConstLabels: prometheus.Labels{ + "cluster": clusterName, + "address": url.String(), + }, }), totalScrapes: prometheus.NewCounter(prometheus.CounterOpts{ Name: prometheus.BuildFQName(namespace, "node_stats", "total_scrapes"), Help: "Current total Elasticsearch node scrapes.", + ConstLabels: prometheus.Labels{ + "cluster": clusterName, + "address": url.String(), + }, }), jsonParseFailures: prometheus.NewCounter(prometheus.CounterOpts{ Name: prometheus.BuildFQName(namespace, "node_stats", "json_parse_failures"), Help: "Number of errors while parsing JSON.", + ConstLabels: prometheus.Labels{ + "cluster": clusterName, + "address": url.String(), + }, }), transportMetrics: []*nodeMetric{ @@ -2275,6 +2287,39 @@ func GetNodeID(client *http.Client, user, password, s string) (string, error) { return "", nil } +func GetClusterName(client *http.Client, user, password, s string) (string, error) { + u, err := url.Parse(s) + if err != nil { + return "", fmt.Errorf("failed to parse URL %s: %s", s, err) + } + if user != "" && password != "" { + u.User = url.UserPassword(user, password) + } + + var cir ClusterInfoResponse + res, err := client.Get(u.String()) + if err != nil { + return "", fmt.Errorf("failed to get cluster info from %s: %s", u.String(), err) + } + defer func() { + err = res.Body.Close() + if err != nil { + log.Println("failed to close response body, err: ", err) + } + }() + if res.StatusCode != http.StatusOK { + return "", fmt.Errorf("HTTP Request failed with code %d", res.StatusCode) + } + bts, err := io.ReadAll(res.Body) + if err != nil { + return "", err + } + if err := json.Unmarshal(bts, &cir); err != nil { + return "", err + } + return cir.ClusterName, nil +} + func GetCatMaster(client *http.Client, user, password, s string) (string, error) { u, err := url.Parse(s) if err != nil { diff --git a/inputs/elasticsearch/collector/nodes_test.go b/inputs/elasticsearch/collector/nodes_test.go index d2fc9c77a..983d736e3 100644 --- a/inputs/elasticsearch/collector/nodes_test.go +++ b/inputs/elasticsearch/collector/nodes_test.go @@ -58,7 +58,7 @@ func TestNodesStats(t *testing.T) { } u.User = url.UserPassword("elastic", "changeme") nodeStats := make([]string, 0) - c := NewNodes(http.DefaultClient, u, true, "_local", false, nodeStats) + c := NewNodes(http.DefaultClient, u, true, "_local", false, nodeStats, "test") nsr, err := c.fetchAndDecodeNodeStats() if err != nil { t.Fatalf("Failed to fetch or decode node stats: %s", err) diff --git a/inputs/elasticsearch/elasticsearch.go b/inputs/elasticsearch/elasticsearch.go index 42c14f275..554918bc6 100644 --- a/inputs/elasticsearch/elasticsearch.go +++ b/inputs/elasticsearch/elasticsearch.go @@ -96,8 +96,9 @@ type ( } serverInfo struct { - nodeID string - masterID string + nodeID string + masterID string + clusterName string } IndicesInfo struct { @@ -204,7 +205,16 @@ func (ins *Instance) Gather(slist *types.SampleList) { return } - slist.PushSample("elasticsearch", "up", 1, map[string]string{"address": s}) + if info.clusterName, err = collector.GetClusterName(ins.Client, ins.UserName, ins.Password, s); err != nil { + slist.PushSample("elasticsearch", "up", 0, map[string]string{"address": s}) + log.Println("E! failed to get cluster name:", err) + return + } + + slist.PushSample("elasticsearch", "up", 1, map[string]string{ + "address": s, + "cluster": info.clusterName, + }) ins.serverInfoMutex.Lock() ins.serverInfo[s] = info ins.serverInfoMutex.Unlock() @@ -272,7 +282,7 @@ func (ins *Instance) Gather(slist *types.SampleList) { } // Always gather node stats - if err := inputs.Collect(collector.NewNodes(ins.Client, EsUrl, ins.AllNodes, ins.Node, ins.Local, ins.NodeStats), slist); err != nil { + if err := inputs.Collect(collector.NewNodes(ins.Client, EsUrl, ins.AllNodes, ins.Node, ins.Local, ins.NodeStats, ins.serverInfo[ins.Node].clusterName), slist); err != nil { log.Println("E! failed to collect nodes metrics:", err) }