enhance/clusterstatus (#44)

fixes #35
This commit is contained in:
T. von Dein
2026-06-22 14:11:32 +02:00
parent 9b5ba0775b
commit a81d6b94e9
2 changed files with 73 additions and 12 deletions

View File

@@ -27,6 +27,8 @@ import (
"codeberg.org/scip/esctl/pkg/cfg"
"codeberg.org/scip/esctl/pkg/printer"
"github.com/dustin/go-humanize"
"github.com/elastic/go-elasticsearch/v9/typedapi/cat/indices"
"github.com/elastic/go-elasticsearch/v9/typedapi/cat/tasks"
"github.com/elastic/go-elasticsearch/v9/typedapi/ccr/stats"
"github.com/elastic/go-elasticsearch/v9/typedapi/cluster/health"
clusterstats "github.com/elastic/go-elasticsearch/v9/typedapi/cluster/stats"
@@ -39,6 +41,8 @@ const (
ResponseInfo
ResponseCcr
ResponseStats
ResponseIndices
ResponseTasks
)
type ClusterIndices map[string]map[string]*types.IndicesRecord
@@ -49,6 +53,8 @@ type apiResponse struct {
health *health.Response
ccr *stats.Response
stats *clusterstats.Response
indices *indices.Response
tasks *tasks.Response
which int
}
@@ -94,7 +100,7 @@ func ClusterList(conf *cfg.Config) error {
// have to do 3 of'em for each cluster. This speeds things up.
func ClusterStatus(conf *cfg.Config) error {
clusters := []string{}
gocount := 3
gocount := 5
if conf.Verbose {
gocount++
}
@@ -120,6 +126,8 @@ func ClusterStatus(conf *cfg.Config) error {
go getClusterData(es, wg, responses, "health")
go getClusterData(es, wg, responses, "info")
go getClusterData(es, wg, responses, "ccrstats")
go getClusterData(es, wg, responses, "indices")
go getClusterData(es, wg, responses, "tasks")
if conf.Verbose {
go getClusterData(es, wg, responses, "stats")
@@ -131,6 +139,8 @@ func ClusterStatus(conf *cfg.Config) error {
var info *info.Response
var ccrstats *stats.Response
var clusterstats *clusterstats.Response
var indexstats *indices.Response
var taskstatus *tasks.Response
for i := 0; i < gocount; i++ {
r := <-responses
@@ -148,11 +158,17 @@ func ClusterStatus(conf *cfg.Config) error {
info = r.info
case ResponseStats:
clusterstats = r.stats
case ResponseIndices:
indexstats = r.indices
case ResponseTasks:
taskstatus = r.tasks
}
}
slog.Debug("ES result", "cluster health", clusterhealth)
isleader := len(ccrstats.AutoFollowStats.AutoFollowedClusters) == 0
ccrfollowing := ""
if len(ccrstats.AutoFollowStats.AutoFollowedClusters) > 0 {
// is following another cluster
@@ -163,6 +179,22 @@ func ClusterStatus(conf *cfg.Config) error {
)
}
// look for red indices, if any
redindices := 0
for _, index := range *indexstats {
if *index.Health == "red" {
redindices++
}
}
// look for long running tasks
longtasks := 0
for _, task := range *taskstatus {
if strings.Contains(*task.RunningTime, "d") {
longtasks++
}
}
table := printer.NewTable(conf, 2, 7)
table.Addheaders(cluster, "status")
@@ -170,10 +202,22 @@ func ClusterStatus(conf *cfg.Config) error {
{"Cluster Name", clusterhealth.ClusterName},
{"ES Status", printer.Colorize(conf, clusterhealth.Status.Name, clusterhealth.Status.Name)},
{"ES Version", info.Version.Int},
{"Is Leader", fmt.Sprintf("%t", isleader)},
{"Active Shards", fmt.Sprintf("%d", clusterhealth.ActiveShards)},
{"Active Primary Shards", fmt.Sprintf("%d", clusterhealth.ActivePrimaryShards)},
{"Unassigned Shards", fmt.Sprintf("%d", clusterhealth.UnassignedShards)},
{"Unassigned Primary Shards", fmt.Sprintf("%d", clusterhealth.UnassignedPrimaryShards)},
{"Pending Tasks", fmt.Sprintf("%d", clusterhealth.NumberOfPendingTasks)},
{"Nodes", fmt.Sprintf("%d", clusterhealth.NumberOfNodes)},
{"Red Indices", fmt.Sprintf("%d", redindices)},
{"Long Running Tasks", fmt.Sprintf("%d", longtasks)},
}
if !isleader {
table.Entries = append(table.Entries, [][]string{
{"AutoFollow (success/failed indices)", ccrfollowing},
{"Followed Indices", fmt.Sprintf("%d", len(ccrstats.FollowStats.Indices))},
}...)
}
if conf.Verbose {
@@ -202,11 +246,8 @@ func gatherClusterStats(conf *cfg.Config, clusterstats *clusterstats.Response, t
clusterstats.Nodes.Jvm.Versions[0].VmVersion}, " ")
}
isleader := checkClusterIsLeader(conf, conf.CurrentCluster)
table.Entries = append(table.Entries, [][]string{
{"Indicies", fmt.Sprintf("%d", clusterstats.Indices.Count)},
{"Is Leader", fmt.Sprintf("%t", isleader)},
{"Docs", fmt.Sprintf("%d", clusterstats.Indices.Docs.Count)},
{"Total Size", humanize.Bytes(uint64(clusterstats.Indices.Docs.TotalSizeInBytes))},
{"Total Queries", fmt.Sprintf("%d", querycount)},
@@ -217,7 +258,7 @@ func gatherClusterStats(conf *cfg.Config, clusterstats *clusterstats.Response, t
humanize.Bytes(uint64(clusterstats.Indices.Store.SizeInBytes)),
humanize.Bytes(uint64(*clusterstats.Indices.Store.TotalDataSetSizeInBytes)),
)},
{"JVM Heap", fmt.Sprintf(
{"JVM Heap Memory", fmt.Sprintf(
"%s/%s",
humanize.Bytes(uint64(clusterstats.Nodes.Jvm.Mem.HeapUsedInBytes)),
humanize.Bytes(uint64(clusterstats.Nodes.Jvm.Mem.HeapMaxInBytes)),

View File

@@ -390,6 +390,26 @@ func getClusterData(es *elasticsearch.TypedClient, wg *sync.WaitGroup, reschan c
ar.stats = res
ar.which = ResponseStats
arerr = err
case "indices":
res, err := es.Cat.Indices().
Header("content-type", "application/json").
Header("accept", "application/json").
Do(context.Background())
ar.indices = &res
ar.which = ResponseIndices
arerr = err
case "tasks":
res, err := es.Cat.Tasks().
Header("content-type", "application/json").
Header("accept", "application/json").
Do(context.Background())
ar.tasks = &res
ar.which = ResponseTasks
arerr = err
}
if arerr != nil {