From f6bab8ec2ed16e592015d5bfba0311aae35c1a97 Mon Sep 17 00:00:00 2001 From: ruochen Date: Tue, 3 Mar 2026 15:04:35 +0800 Subject: [PATCH 1/6] =?UTF-8?q?feat:=20elasticsearch=5Fup=20=E6=8C=87?= =?UTF-8?q?=E6=A0=87=E6=B7=BB=E5=8A=A0cluster=E6=A0=87=E7=AD=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: ruochen --- inputs/elasticsearch/collector/nodes.go | 33 +++++++++++++++++++++++++ inputs/elasticsearch/elasticsearch.go | 15 ++++++++--- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/inputs/elasticsearch/collector/nodes.go b/inputs/elasticsearch/collector/nodes.go index 4a5cb3afd..398b41e3f 100644 --- a/inputs/elasticsearch/collector/nodes.go +++ b/inputs/elasticsearch/collector/nodes.go @@ -2275,6 +2275,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 http.Client, 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/elasticsearch.go b/inputs/elasticsearch/elasticsearch.go index 42c14f275..41272561b 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,15 @@ 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) + } + + slist.PushSample("elasticsearch", "up", 1, map[string]string{ + "address": s, + "cluster": info.clusterName, + }) ins.serverInfoMutex.Lock() ins.serverInfo[s] = info ins.serverInfoMutex.Unlock() From d540942cad150b5f4ca920c2d957bcde0187396b Mon Sep 17 00:00:00 2001 From: ruochen Date: Tue, 3 Mar 2026 15:50:51 +0800 Subject: [PATCH 2/6] =?UTF-8?q?feat:=20elasticsearch=5Fnode=5Fstats=5Fup?= =?UTF-8?q?=20elasticsearch=5Fnode=5Fstats=5Ftotal=5Fscrapes=20=20?= =?UTF-8?q?=E6=8C=87=E6=A0=87=E6=B7=BB=E5=8A=A0cluster=E6=A0=87=E7=AD=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: ruochen --- inputs/elasticsearch/collector/nodes.go | 17 ++++++++++------- inputs/elasticsearch/collector/nodes_test.go | 2 +- inputs/elasticsearch/elasticsearch.go | 7 ++++++- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/inputs/elasticsearch/collector/nodes.go b/inputs/elasticsearch/collector/nodes.go index 398b41e3f..6088c3048 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, @@ -207,16 +207,19 @@ func NewNodes(client *http.Client, url *url.URL, all bool, node string, local bo nodeStats: nodeStats, up: prometheus.NewGauge(prometheus.GaugeOpts{ - Name: prometheus.BuildFQName(namespace, "node_stats", "up"), - Help: "Was the last scrape of the Elasticsearch nodes endpoint successful.", + Name: prometheus.BuildFQName(namespace, "node_stats", "up"), + Help: "Was the last scrape of the Elasticsearch nodes endpoint successful.", + ConstLabels: prometheus.Labels{"cluster": clusterName}, }), totalScrapes: prometheus.NewCounter(prometheus.CounterOpts{ - Name: prometheus.BuildFQName(namespace, "node_stats", "total_scrapes"), - Help: "Current total Elasticsearch node scrapes.", + Name: prometheus.BuildFQName(namespace, "node_stats", "total_scrapes"), + Help: "Current total Elasticsearch node scrapes.", + ConstLabels: prometheus.Labels{"cluster": clusterName}, }), jsonParseFailures: prometheus.NewCounter(prometheus.CounterOpts{ - Name: prometheus.BuildFQName(namespace, "node_stats", "json_parse_failures"), - Help: "Number of errors while parsing JSON.", + Name: prometheus.BuildFQName(namespace, "node_stats", "json_parse_failures"), + Help: "Number of errors while parsing JSON.", + ConstLabels: prometheus.Labels{"cluster": clusterName}, }), transportMetrics: []*nodeMetric{ 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 41272561b..339f8ab15 100644 --- a/inputs/elasticsearch/elasticsearch.go +++ b/inputs/elasticsearch/elasticsearch.go @@ -280,8 +280,13 @@ func (ins *Instance) Gather(slist *types.SampleList) { ins.NewIndicesInclude = ins.IndicesInclude } + var clusterName string + if clusterName, err = collector.GetClusterName(ins.Client, ins.UserName, ins.Password, s); err != nil { + log.Println("E! failed to get cluster name:", err) + } + // 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, clusterName), slist); err != nil { log.Println("E! failed to collect nodes metrics:", err) } From 0518f970175e70b03b40551628639b16a3ce212d Mon Sep 17 00:00:00 2001 From: ruochen Date: Tue, 3 Mar 2026 15:53:03 +0800 Subject: [PATCH 3/6] =?UTF-8?q?fix:=20=E5=8E=BB=E9=99=A4=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=20clustername=20=E7=9A=84=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: ruochen --- inputs/elasticsearch/elasticsearch.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/inputs/elasticsearch/elasticsearch.go b/inputs/elasticsearch/elasticsearch.go index 339f8ab15..af0f29a06 100644 --- a/inputs/elasticsearch/elasticsearch.go +++ b/inputs/elasticsearch/elasticsearch.go @@ -280,13 +280,8 @@ func (ins *Instance) Gather(slist *types.SampleList) { ins.NewIndicesInclude = ins.IndicesInclude } - var clusterName string - if clusterName, err = collector.GetClusterName(ins.Client, ins.UserName, ins.Password, s); err != nil { - log.Println("E! failed to get cluster name:", err) - } - // Always gather node stats - if err := inputs.Collect(collector.NewNodes(ins.Client, EsUrl, ins.AllNodes, ins.Node, ins.Local, ins.NodeStats, clusterName), 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) } From 7f12bb38964362a940e9764ad3ba035dedebb633 Mon Sep 17 00:00:00 2001 From: kongfei605 Date: Tue, 3 Mar 2026 16:04:48 +0800 Subject: [PATCH 4/6] chore(elasticsearch): update logs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- inputs/elasticsearch/collector/nodes.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inputs/elasticsearch/collector/nodes.go b/inputs/elasticsearch/collector/nodes.go index 6088c3048..cf199d866 100644 --- a/inputs/elasticsearch/collector/nodes.go +++ b/inputs/elasticsearch/collector/nodes.go @@ -2295,7 +2295,7 @@ func GetClusterName(client *http.Client, user, password, s string) (string, erro defer func() { err = res.Body.Close() if err != nil { - log.Println("failed to close http.Client, err: ", err) + log.Println("failed to close response body, err: ", err) } }() if res.StatusCode != http.StatusOK { From 8472cd536048f7945ff921febfc46d524514f6ae Mon Sep 17 00:00:00 2001 From: kongfei605 Date: Tue, 3 Mar 2026 16:13:35 +0800 Subject: [PATCH 5/6] fix(elasticsearch): error handling for cluster name retrieval --- inputs/elasticsearch/elasticsearch.go | 1 + 1 file changed, 1 insertion(+) diff --git a/inputs/elasticsearch/elasticsearch.go b/inputs/elasticsearch/elasticsearch.go index af0f29a06..554918bc6 100644 --- a/inputs/elasticsearch/elasticsearch.go +++ b/inputs/elasticsearch/elasticsearch.go @@ -208,6 +208,7 @@ func (ins *Instance) Gather(slist *types.SampleList) { 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{ From b4df3fca83832a9ee01de501530f516fc852d8fb Mon Sep 17 00:00:00 2001 From: ruochen Date: Tue, 3 Mar 2026 16:26:37 +0800 Subject: [PATCH 6/6] =?UTF-8?q?feat:=20elasticsearch=5Fnode=5Fstats=5Fup?= =?UTF-8?q?=20elasticsearch=5Fnode=5Fstats=5Ftotal=5Fscrapes=20=20?= =?UTF-8?q?=E6=8C=87=E6=A0=87=E6=B7=BB=E5=8A=A0=20address=20=E6=A0=87?= =?UTF-8?q?=E7=AD=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: ruochen --- inputs/elasticsearch/collector/nodes.go | 27 ++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/inputs/elasticsearch/collector/nodes.go b/inputs/elasticsearch/collector/nodes.go index cf199d866..90dc14cd9 100644 --- a/inputs/elasticsearch/collector/nodes.go +++ b/inputs/elasticsearch/collector/nodes.go @@ -207,19 +207,28 @@ func NewNodes(client *http.Client, url *url.URL, all bool, node string, local bo nodeStats: nodeStats, 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}, + 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}, + 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}, + 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{