diff --git a/TODO.md b/TODO.md
index 87ad16a..f42e3bb 100644
--- a/TODO.md
+++ b/TODO.md
@@ -11,3 +11,5 @@
https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-get-data-stream
also exclude data stream backing indices from index ls
+
+- table any2string
diff --git a/cmd/root.go b/cmd/root.go
index 4f95c8c..2eac0a1 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -89,7 +89,7 @@ func Main() int {
Name: "output",
Aliases: []string{"o"},
Value: "",
- Usage: "output mode (tsv, markdown, json, yaml) default: tsv",
+ Usage: "output mode (tsv, json, yaml) default: tsv",
Destination: &conf.Output,
},
&cli.StringFlag{
diff --git a/go.mod b/go.mod
index e8116bb..152498b 100644
--- a/go.mod
+++ b/go.mod
@@ -19,6 +19,8 @@ go 1.25.8
require (
github.com/MichaelMure/go-term-markdown v0.1.4
github.com/alecthomas/repr v0.5.2
+ github.com/charmbracelet/bubbles v1.0.0
+ github.com/charmbracelet/bubbletea v1.3.10
github.com/charmbracelet/lipgloss v1.1.0
github.com/chzyer/readline v1.5.1
github.com/dustin/go-humanize v1.0.1
@@ -29,10 +31,11 @@ require (
github.com/go-openapi/spec v0.22.5
github.com/go-openapi/swag/loading v0.26.1
github.com/mattn/go-isatty v0.0.22
- github.com/olekukonko/tablewriter v1.1.4
+ github.com/seeruk/go-wordwrap v0.0.0-20191208221741-14ec4aac9550
github.com/tidwall/gjson v1.19.0
github.com/tlinden/yadu v0.1.3
github.com/urfave/cli/v3 v3.10.1-0.20260623012112-f980ca84bf65
+ golang.org/x/term v0.44.0
gopkg.in/yaml.v3 v3.0.1
)
@@ -40,9 +43,6 @@ require (
github.com/MichaelMure/go-term-text v0.3.1 // indirect
github.com/alecthomas/chroma v0.7.1 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
- github.com/cespare/xxhash/v2 v2.3.0 // indirect
- github.com/charmbracelet/bubbles v1.0.0 // indirect
- github.com/charmbracelet/bubbletea v1.3.10 // indirect
github.com/charmbracelet/colorprofile v0.4.1 // indirect
github.com/charmbracelet/x/ansi v0.11.6 // indirect
github.com/charmbracelet/x/cellbuf v0.0.15 // indirect
@@ -69,7 +69,6 @@ require (
github.com/go-openapi/swag/typeutils v0.26.1 // indirect
github.com/go-openapi/swag/yamlutils v0.26.1 // indirect
github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
- github.com/goccy/go-json v0.10.6 // indirect
github.com/gomarkdown/markdown v0.0.0-20191123064959-2c17d62f5098 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/kyokomi/emoji/v2 v2.2.8 // indirect
@@ -81,11 +80,7 @@ require (
github.com/muesli/cancelreader v0.2.2 // indirect
github.com/muesli/termenv v0.16.0 // indirect
github.com/oklog/ulid/v2 v2.1.1 // indirect
- github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 // indirect
- github.com/olekukonko/errors v1.2.0 // indirect
- github.com/olekukonko/ll v0.1.8 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
- github.com/seeruk/go-wordwrap v0.0.0-20191208221741-14ec4aac9550 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
@@ -94,10 +89,8 @@ require (
go.opentelemetry.io/otel/metric v1.35.0 // indirect
go.opentelemetry.io/otel/trace v1.35.0 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
- golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
golang.org/x/image v0.0.0-20191206065243-da761ea9ff43 // indirect
golang.org/x/net v0.55.0 // indirect
golang.org/x/sys v0.46.0 // indirect
- golang.org/x/term v0.44.0 // indirect
golang.org/x/text v0.37.0 // indirect
)
diff --git a/go.sum b/go.sum
index 2918b3b..5f7026b 100644
--- a/go.sum
+++ b/go.sum
@@ -14,28 +14,18 @@ github.com/alecthomas/repr v0.5.2 h1:SU73FTI9D1P5UNtvseffFSGmdNci/O6RsqzeXJtP0Qs
github.com/alecthomas/repr v0.5.2/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
-github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
-github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/charmbracelet/bubbles v1.0.0 h1:12J8/ak/uCZEMQ6KU7pcfwceyjLlWsDLAxB5fXonfvc=
github.com/charmbracelet/bubbles v1.0.0/go.mod h1:9d/Zd5GdnauMI5ivUIVisuEm3ave1XwXtD1ckyV6r3E=
github.com/charmbracelet/bubbletea v1.3.10 h1:otUDHWMMzQSB0Pkc87rm691KZ3SWa4KUlvF9nRvCICw=
github.com/charmbracelet/bubbletea v1.3.10/go.mod h1:ORQfo0fk8U+po9VaNvnV95UPWA1BitP1E0N6xJPlHr4=
-github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs=
-github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk=
github.com/charmbracelet/colorprofile v0.4.1 h1:a1lO03qTrSIRaK8c3JRxJDZOvhvIeSco3ej+ngLk1kk=
github.com/charmbracelet/colorprofile v0.4.1/go.mod h1:U1d9Dljmdf9DLegaJ0nGZNJvoXAhayhmidOdcBwAvKk=
github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY=
github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
-github.com/charmbracelet/x/ansi v0.8.0 h1:9GTq3xq9caJW8ZrBTe0LIe2fvfLR/bYXKTx2llXn7xE=
-github.com/charmbracelet/x/ansi v0.8.0/go.mod h1:wdYl/ONOLHLIVmQaxbIYEC/cRKOQyjTkowiI4blgS9Q=
github.com/charmbracelet/x/ansi v0.11.6 h1:GhV21SiDz/45W9AnV2R61xZMRri5NlLnl6CVF7ihZW8=
github.com/charmbracelet/x/ansi v0.11.6/go.mod h1:2JNYLgQUsyqaiLovhU2Rv/pb8r6ydXKS3NIttu3VGZQ=
-github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8=
-github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
github.com/charmbracelet/x/cellbuf v0.0.15 h1:ur3pZy0o6z/R7EylET877CBxaiE1Sp1GMxoFPAIztPI=
github.com/charmbracelet/x/cellbuf v0.0.15/go.mod h1:J1YVbR7MUuEGIFPCaaZ96KDl5NoS0DAWkskup+mOY+Q=
-github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
-github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk=
github.com/charmbracelet/x/term v0.2.2/go.mod h1:kF8CY5RddLWrsgVwpw4kAa6TESp6EB5y3uxGLeCqzAI=
github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM=
@@ -114,8 +104,6 @@ github.com/go-openapi/testify/v2 v2.5.1 h1:TMdhCaw8fUNraVSf3Omoob1dO/AzBfhtFAPW0
github.com/go-openapi/testify/v2 v2.5.1/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw=
github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro=
github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
-github.com/goccy/go-json v0.10.6 h1:p8HrPJzOakx/mn/bQtjgNjdTcN+/S6FcG2CTtQOrHVU=
-github.com/goccy/go-json v0.10.6/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/gomarkdown/markdown v0.0.0-20191123064959-2c17d62f5098 h1:Qxs3bNRWe8GTcKMxYOSXm0jx6j0de8XUtb/fsP3GZ0I=
github.com/gomarkdown/markdown v0.0.0-20191123064959-2c17d62f5098/go.mod h1:aii0r/K0ZnHv7G0KF7xy1v0A7s2Ljrb5byB7MO5p6TU=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
@@ -154,14 +142,6 @@ github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
github.com/oklog/ulid/v2 v2.1.1 h1:suPZ4ARWLOJLegGFiZZ1dFAkqzhMjL3J1TzI+5wHz8s=
github.com/oklog/ulid/v2 v2.1.1/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ=
-github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 h1:zrbMGy9YXpIeTnGj4EljqMiZsIcE09mmF8XsD5AYOJc=
-github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6/go.mod h1:rEKTHC9roVVicUIfZK7DYrdIoM0EOr8mK1Hj5s3JjH0=
-github.com/olekukonko/errors v1.2.0 h1:10Zcn4GeV59t/EGqJc8fUjtFT/FuUh5bTMzZ1XwmCRo=
-github.com/olekukonko/errors v1.2.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=
-github.com/olekukonko/ll v0.1.8 h1:ysHCJRGHYKzmBSdz9w5AySztx7lG8SQY+naTGYUbsz8=
-github.com/olekukonko/ll v0.1.8/go.mod h1:RPRC6UcscfFZgjo1nulkfMH5IM0QAYim0LfnMvUuozw=
-github.com/olekukonko/tablewriter v1.1.4 h1:ORUMI3dXbMnRlRggJX3+q7OzQFDdvgbN9nVWj1drm6I=
-github.com/olekukonko/tablewriter v1.1.4/go.mod h1:+kedxuyTtgoZLwif3P1Em4hARJs+mVnzKxmsCL/C5RY=
github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -189,8 +169,6 @@ github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tlinden/yadu v0.1.3 h1:5cRCUmj+l5yvlM2irtpFBIJwVV2DPEgYSaWvF19FtcY=
github.com/tlinden/yadu v0.1.3/go.mod h1:l3bRmHKL9zGAR6pnBHY2HRPxBecf7L74BoBgOOpTcUA=
-github.com/urfave/cli/v3 v3.9.1-0.20260524212652-be8b79d0c8de h1:ESKPiS7inVoBnv4FmgGNZdjWBI/wmvaragoyD3D9nM4=
-github.com/urfave/cli/v3 v3.9.1-0.20260524212652-be8b79d0c8de/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso=
github.com/urfave/cli/v3 v3.10.1-0.20260623012112-f980ca84bf65 h1:NXitXXO9DupDLEFj8hIyYtsubRxSFTp5JXqohElT0nU=
github.com/urfave/cli/v3 v3.10.1-0.20260623012112-f980ca84bf65/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
@@ -223,8 +201,6 @@ golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY=
-golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc=
diff --git a/pkg/es/ccr.go b/pkg/es/ccr.go
index 788fd95..ca7c5a4 100644
--- a/pkg/es/ccr.go
+++ b/pkg/es/ccr.go
@@ -113,11 +113,11 @@ func CcrRemoteInfo(conf *cfg.Config, index string) error {
table := printer.NewTable(conf, 2, 5)
table.Addheaders("ccr remote property", "value")
- table.Entries = [][]string{
+ table.Entries = [][]any{
{"Remote Cluster", remote},
{"CCR Mode", mode},
- {"Connected", fmt.Sprintf("%t", info.Connected)},
- {"Num Proxy Sockets Connected", fmt.Sprintf("%d", info.NumProxySocketsConnected)},
+ {"Connected", info.Connected},
+ {"Num Proxy Sockets Connected", info.NumProxySocketsConnected},
{"Proxy Address", info.ProxyAddress},
}
diff --git a/pkg/es/ccr_follower.go b/pkg/es/ccr_follower.go
index e324142..e8bb674 100644
--- a/pkg/es/ccr_follower.go
+++ b/pkg/es/ccr_follower.go
@@ -164,16 +164,16 @@ func CcrFollowerShow(conf *cfg.Config, index string) error {
table := printer.NewTable(conf, 2, 9)
table.Addheaders("ccr follower property", "value")
- table.Entries = [][]string{
+ table.Entries = [][]any{
{"name", index},
{"remote_cluster", follower.RemoteCluster},
- {"leader_checkpoint", fmt.Sprintf("%d", follower.LeaderGlobalCheckpoint)},
- {"follower_checkpoint", fmt.Sprintf("%d", follower.FollowerGlobalCheckpoint)},
- {"bytes_read", fmt.Sprintf("%d", follower.BytesRead)},
- {"failed_read_requests", fmt.Sprintf("%d", follower.FailedReadRequests)},
- {"failed_write_requests", fmt.Sprintf("%d", follower.FailedWriteRequests)},
- {"successful_read_requests", fmt.Sprintf("%d", follower.SuccessfulReadRequests)},
- {"successful_write_requests", fmt.Sprintf("%d", follower.SuccessfulWriteRequests)},
+ {"leader_checkpoint", follower.LeaderGlobalCheckpoint},
+ {"follower_checkpoint", follower.FollowerGlobalCheckpoint},
+ {"bytes_read", follower.BytesRead},
+ {"failed_read_requests", follower.FailedReadRequests},
+ {"failed_write_requests", follower.FailedWriteRequests},
+ {"successful_read_requests", follower.SuccessfulReadRequests},
+ {"successful_write_requests", follower.SuccessfulWriteRequests},
}
if err := table.Print(); err != nil {
diff --git a/pkg/es/cluster.go b/pkg/es/cluster.go
index 8895e50..ac8904b 100644
--- a/pkg/es/cluster.go
+++ b/pkg/es/cluster.go
@@ -81,7 +81,7 @@ func ClusterList(conf *cfg.Config) error {
}
}
- table.Entries[idx] = []string{name, cluster.Uri, reachableStr, current, errmsg}
+ table.Entries[idx] = []any{name, cluster.Uri, reachableStr, current, errmsg}
idx++
}
@@ -190,25 +190,25 @@ func ClusterStatus(conf *cfg.Config) error {
table := printer.NewTable(conf, 2, 7)
table.Addheaders(conf.DefaultCluster.Name, "status")
- table.Entries = [][]string{
+ table.Entries = [][]any{
{"Cluster Name", res.health.ClusterName},
{"ES Status", printer.Colorize(conf, res.health.Status.Name, res.health.Status.Name)},
{"ES Version", res.info.Version.Int},
- {"Is Leader", fmt.Sprintf("%t", isleader)},
- {"Active Shards", fmt.Sprintf("%d", res.health.ActiveShards)},
- {"Active Primary Shards", fmt.Sprintf("%d", res.health.ActivePrimaryShards)},
- {"Unassigned Shards", fmt.Sprintf("%d", res.health.UnassignedShards)},
- {"Unassigned Primary Shards", fmt.Sprintf("%d", res.health.UnassignedPrimaryShards)},
- {"Pending Tasks", fmt.Sprintf("%d", res.health.NumberOfPendingTasks)},
- {"Nodes", fmt.Sprintf("%d", res.health.NumberOfNodes)},
- {"Red Indices", fmt.Sprintf("%d", redindices)},
- {"Long Running Tasks", fmt.Sprintf("%d", longtasks)},
+ {"Is Leader", isleader},
+ {"Active Shards", res.health.ActiveShards},
+ {"Active Primary Shards", res.health.ActivePrimaryShards},
+ {"Unassigned Shards", res.health.UnassignedShards},
+ {"Unassigned Primary Shards", res.health.UnassignedPrimaryShards},
+ {"Pending Tasks", res.health.NumberOfPendingTasks},
+ {"Nodes", res.health.NumberOfNodes},
+ {"Red Indices", redindices},
+ {"Long Running Tasks", longtasks},
}
if !isleader && res.ccr != nil {
- table.Entries = append(table.Entries, [][]string{
+ table.Entries = append(table.Entries, [][]any{
{"AutoFollow (success/failed indices)", ccrfollowing},
- {"Followed Indices", fmt.Sprintf("%d", len(res.ccr.FollowStats.Indices))},
+ {"Followed Indices", len(res.ccr.FollowStats.Indices)},
}...)
}
@@ -219,15 +219,15 @@ func ClusterStatus(conf *cfg.Config) error {
if res.health.Status.Name != "green" {
for name, indicator := range res.healthreport.Indicators {
if indicator.Status != "green" {
- table.Entries = append(table.Entries, []string{
+ table.Entries = append(table.Entries, []any{
printer.Colorize(conf, indicator.Status, "Bad health "+name), indicator.Symptom,
})
for _, diag := range indicator.Diagnosis {
- table.Entries = append(table.Entries, []string{" -> cause", diag.Cause})
+ table.Entries = append(table.Entries, []any{" -> cause", diag.Cause})
for resource, items := range diag.AffectedResources {
- table.Entries = append(table.Entries, []string{" -> affected " + resource, strings.Join(items, ",")})
+ table.Entries = append(table.Entries, []any{" -> affected " + resource, strings.Join(items, ",")})
}
}
}
@@ -255,13 +255,13 @@ func gatherClusterStats(conf *cfg.Config, clusterstats *clusterstats.Response, t
clusterstats.Nodes.Jvm.Versions[0].VmVersion}, " ")
}
- table.Entries = append(table.Entries, [][]string{
- {"Indicies", fmt.Sprintf("%d", clusterstats.Indices.Count)},
- {"Docs", fmt.Sprintf("%d", clusterstats.Indices.Docs.Count)},
- {"Total Size", humanize.Bytes(uint64(clusterstats.Indices.Docs.TotalSizeInBytes))},
- {"Total Queries", fmt.Sprintf("%d", querycount)},
- {"Shards Primaries", fmt.Sprintf("%d", clusterstats.Indices.Shards.Primaries)},
- {"Shards Total", fmt.Sprintf("%d", clusterstats.Indices.Shards.Total)},
+ table.Entries = append(table.Entries, [][]any{
+ {"Indicies", clusterstats.Indices.Count},
+ {"Docs", clusterstats.Indices.Docs.Count},
+ {"Total Size", printer.Bytes(clusterstats.Indices.Docs.TotalSizeInBytes)},
+ {"Total Queries", "%d", querycount},
+ {"Shards Primaries", clusterstats.Indices.Shards.Primaries},
+ {"Shards Total", clusterstats.Indices.Shards.Total},
{"Storage", fmt.Sprintf(
"%s/%s",
humanize.Bytes(uint64(clusterstats.Indices.Store.SizeInBytes)),
@@ -272,11 +272,11 @@ func gatherClusterStats(conf *cfg.Config, clusterstats *clusterstats.Response, t
humanize.Bytes(uint64(clusterstats.Nodes.Jvm.Mem.HeapUsedInBytes)),
humanize.Bytes(uint64(clusterstats.Nodes.Jvm.Mem.HeapMaxInBytes)),
)},
- {"JVM Threads", fmt.Sprintf("%d", clusterstats.Nodes.Jvm.Threads)},
+ {"JVM Threads", clusterstats.Nodes.Jvm.Threads},
{"JVM Version", vmversion},
- {"CPUs", fmt.Sprintf("%d", clusterstats.Nodes.Os.AllocatedProcessors)},
+ {"CPUs", clusterstats.Nodes.Os.AllocatedProcessors},
{"CPU Usage", fmt.Sprintf("%d%%", clusterstats.Nodes.Process.Cpu.Percent)},
- {"Open FDs", fmt.Sprintf("%d", clusterstats.Nodes.Process.OpenFileDescriptors.Avg)},
+ {"Open FDs", clusterstats.Nodes.Process.OpenFileDescriptors.Avg},
}...)
return table
diff --git a/pkg/es/cluster_settings.go b/pkg/es/cluster_settings.go
index e2a1d77..8941221 100644
--- a/pkg/es/cluster_settings.go
+++ b/pkg/es/cluster_settings.go
@@ -40,7 +40,7 @@ func ClusterSettingsList(conf *cfg.Config) error {
table := printer.NewTable(conf, 2, 0)
table.Addheaders("setting", "value")
- entries := [][]string{}
+ entries := [][]any{}
settingshash := res.Persistent // == map[string]json.RawMessage
@@ -52,7 +52,7 @@ func ClusterSettingsList(conf *cfg.Config) error {
}
for topic, val := range settingshash {
- entries = append(entries, []string{topic, string(val)})
+ entries = append(entries, []any{topic, string(val)})
}
table.Entries = entries
diff --git a/pkg/es/cluster_util.go b/pkg/es/cluster_util.go
index 8800c92..e72115e 100644
--- a/pkg/es/cluster_util.go
+++ b/pkg/es/cluster_util.go
@@ -72,27 +72,27 @@ func checkClusterStatus(conf *cfg.Config, leader, follower string) bool {
table.Addheaders("setting", "leader:"+leader, "follower:"+follower)
- table.Entries = [][]string{
+ table.Entries = [][]any{
{"Cluster Name", status[leader].ClusterName, status[follower].ClusterName},
{"Cluster Status",
printer.Colorize(conf, status[leader].Status.Name, status[leader].Status.Name),
printer.Colorize(conf, status[follower].Status.Name, status[follower].Status.Name),
},
{"Active Shards",
- fmt.Sprintf("%d", status[leader].ActiveShards),
- fmt.Sprintf("%d", status[follower].ActiveShards),
+ status[leader].ActiveShards,
+ status[follower].ActiveShards,
},
{"Active Primary Shards",
- fmt.Sprintf("%d", status[leader].ActivePrimaryShards),
- fmt.Sprintf("%d", status[follower].ActivePrimaryShards),
+ status[leader].ActivePrimaryShards,
+ status[follower].ActivePrimaryShards,
},
{"Indicies",
- fmt.Sprintf("%d", len(status[leader].Indices)),
- fmt.Sprintf("%d", len(status[follower].Indices)),
+ len(status[leader].Indices),
+ len(status[follower].Indices),
},
{"Nodes",
- fmt.Sprintf("%d", status[leader].NumberOfNodes),
- fmt.Sprintf("%d", status[follower].NumberOfNodes),
+ status[leader].NumberOfNodes,
+ status[follower].NumberOfNodes,
},
}
@@ -112,7 +112,7 @@ func checkClusterStatus(conf *cfg.Config, leader, follower string) bool {
// finds indices on both clusters which have ilm errors
func findIlmErrors(conf *cfg.Config, leader, follower string) bool {
- failed := map[string]map[string]string{}
+ failed := map[string]map[string]any{}
for _, cluster := range []string{leader, follower} {
ilm, err := conf.Clusters[cluster].ES().Ilm.ExplainLifecycle("_all").
@@ -123,13 +123,13 @@ func findIlmErrors(conf *cfg.Config, leader, follower string) bool {
return false
}
- failed[cluster] = map[string]string{}
+ failed[cluster] = map[string]any{}
for name, ilmstate := range ilm.Indices {
count := ilmstate.(*types.LifecycleExplainManaged).FailedStepRetryCount
if count != nil && *count > 0 {
- failed[cluster][name] = fmt.Sprintf("%d", *count)
+ failed[cluster][name] = *count
}
}
}
@@ -150,7 +150,7 @@ func findIlmErrors(conf *cfg.Config, leader, follower string) bool {
table.Addheaders("ilm errors on "+which, "errors")
for name, count := range failed[cluster] {
- table.Entries[idx] = []string{name, count}
+ table.Entries[idx] = []any{name, count}
idx++
}
@@ -222,7 +222,7 @@ func findIndicesOnlyOnLeader(conf *cfg.Config, indices ClusterIndices, leader, f
for name, index := range indexOnlyOnLeader {
name := printer.Colorize(conf, "red", name)
- table.Entries[idx] = []string{name, *index.DatasetSize, *index.DocsCount}
+ table.Entries[idx] = []any{name, *index.DatasetSize, *index.DocsCount}
idx++
}
@@ -270,7 +270,7 @@ func findOrphanedIndices(conf *cfg.Config, indices ClusterIndices, leader, follo
for name, index := range orphaned {
name := printer.Colorize(conf, "red", name)
- table.Entries[idx] = []string{name, *index.DatasetSize, *index.DocsCount}
+ table.Entries[idx] = []any{name, *index.DatasetSize, *index.DocsCount}
idx++
}
@@ -304,7 +304,7 @@ func findFailedFollowerIndices(conf *cfg.Config, indices ClusterIndices, followe
for name, index := range red {
name := printer.Colorize(conf, "red", name)
- table.Entries[idx] = []string{name, *index.DatasetSize, *index.DocsCount}
+ table.Entries[idx] = []any{name, *index.DatasetSize, *index.DocsCount}
idx++
}
diff --git a/pkg/es/datastream.go b/pkg/es/datastream.go
index a0a1a83..78b1e18 100644
--- a/pkg/es/datastream.go
+++ b/pkg/es/datastream.go
@@ -25,7 +25,6 @@ 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/types"
)
@@ -73,13 +72,13 @@ func DatastreamList(conf *cfg.Config) error {
policy = *ds.IlmPolicy
}
- table.Entries[idx] = []string{
+ table.Entries[idx] = []any{
name,
policy,
- fmt.Sprintf("%t", ds.Hidden),
- fmt.Sprintf("%t", *ds.System),
- fmt.Sprintf("%t", *ds.Replicated),
- fmt.Sprintf("%d", ds.Generation),
+ ds.Hidden,
+ *ds.System,
+ *ds.Replicated,
+ ds.Generation,
ds.TimestampField.Name,
}
@@ -156,18 +155,18 @@ func DatastreamShow(conf *cfg.Config, dsname string) error {
policy = *ds.IlmPolicy
}
- table.Entries = [][]string{
+ table.Entries = [][]any{
{"name", name},
{"ilm policy", policy},
- {"hidden", fmt.Sprintf("%t", ds.Hidden)},
- {"system", fmt.Sprintf("%t", *ds.System)},
- {"replicated", fmt.Sprintf("%t", *ds.Replicated)},
- {"generation", fmt.Sprintf("%d", ds.Generation)},
+ {"hidden", ds.Hidden},
+ {"system", *ds.System},
+ {"replicated", *ds.Replicated},
+ {"generation", ds.Generation},
{"timestamp field", ds.TimestampField.Name},
- {"backing indices", fmt.Sprintf("%d", stats.BackingIndices)},
- {"size", humanize.Bytes(uint64(stats.TotalStoreSizeBytes))},
- {"shards-failed", fmt.Sprintf("%d", stats.Shards_.Failed)},
- {"shards-successful", fmt.Sprintf("%d", stats.Shards_.Successful)},
+ {"backing indices", stats.BackingIndices},
+ {"size", printer.Bytes(stats.TotalStoreSizeBytes)},
+ {"shards-failed", stats.Shards_.Failed},
+ {"shards-successful", stats.Shards_.Successful},
}
if err := table.Print(); err != nil {
@@ -183,10 +182,10 @@ func DatastreamShow(conf *cfg.Config, dsname string) error {
policy = *ds.IlmPolicy
}
- table.Entries[idx] = []string{
+ table.Entries[idx] = []any{
index.IndexName,
index.IndexUuid,
- fmt.Sprintf("%t", *index.PreferIlm),
+ *index.PreferIlm,
policy,
index.ManagedBy.Name,
}
@@ -235,10 +234,10 @@ func DatastreamRollover(conf *cfg.Config, ds string) error {
table := printer.NewTable(conf, 2, 5)
table.Addheaders("rollover response", "value")
- table.Entries = [][]string{
- {"acknowledged", fmt.Sprintf("%t", res.Acknowledged)},
- {"rolled over", fmt.Sprintf("%t", res.RolledOver)},
- {"shards acknowledged", fmt.Sprintf("%t", res.ShardsAcknowledged)},
+ table.Entries = [][]any{
+ {"acknowledged", res.Acknowledged},
+ {"rolled over", res.RolledOver},
+ {"shards acknowledged", res.ShardsAcknowledged},
{"old index", res.OldIndex},
{"new index", res.NewIndex},
}
diff --git a/pkg/es/ilm.go b/pkg/es/ilm.go
index b0fbd08..e82067d 100644
--- a/pkg/es/ilm.go
+++ b/pkg/es/ilm.go
@@ -129,7 +129,7 @@ func IlmShow(conf *cfg.Config, policy string) error {
table := printer.NewTable(conf, 2, 5)
table.Addheaders("ilm policy setting", "value")
- table.Entries = [][]string{
+ table.Entries = [][]any{
{"policy", policy},
{"hot phase", ilmPhaseString(ilm.Policy.Phases.Hot, false)},
{"warm phase", ilmPhaseString(ilm.Policy.Phases.Warm, false)},
@@ -291,17 +291,17 @@ func IlmExplain(conf *cfg.Config, index string) error {
return fmt.Errorf("failed to unmarshal step info: %w", err)
}
- table.Entries = [][]string{
+ table.Entries = [][]any{
{"index", ilm.Index},
{"ilm policy", *ilm.Policy},
{"action", *ilm.Action},
- {"age", fmt.Sprintf("%s", ilm.Age)},
- {"managed", fmt.Sprintf("%t", ilm.Managed)},
+ {"age", ilm.Age},
+ {"managed", ilm.Managed},
{"phase", *ilm.Phase},
{"phase execution", ilmPhaseString(ilm.PhaseExecution.PhaseDefinition, false)},
{"step", *ilm.Step},
{"failed step", *ilm.FailedStep},
- {"failed step retry count", fmt.Sprintf("%d", ilm.FailedStepRetryCount)},
+ {"failed step retry count", ilm.FailedStepRetryCount},
}
if err := table.Print(); err != nil {
diff --git a/pkg/es/ilm_forecast.go b/pkg/es/ilm_forecast.go
index 569bf2d..63d9faa 100644
--- a/pkg/es/ilm_forecast.go
+++ b/pkg/es/ilm_forecast.go
@@ -119,13 +119,13 @@ func IlmForecastList(conf *cfg.Config, filter string) error {
virtualAge := virtualAge(&phase)
- row := []string{
+ row := []any{
phase.index,
- humanize.Bytes(uint64(phase.size)),
+ printer.Bytes(phase.size),
formatDuration(phase.age),
formatDuration(virtualAge),
formatDuration(phase.minage),
- humanize.Bytes(uint64(phase.minsize)),
+ printer.Bytes(phase.minsize),
phase.currentPhase,
phase.nextPhase,
}
diff --git a/pkg/es/index.go b/pkg/es/index.go
index be8a6d4..2d16ef6 100644
--- a/pkg/es/index.go
+++ b/pkg/es/index.go
@@ -118,7 +118,7 @@ func IndexList(conf *cfg.Config) error {
for idx, index := range list {
name := printer.Colorize(conf, *index.Health, *index.Index)
- table.Entries[idx] = []string{name, *index.DatasetSize, *index.DocsCount}
+ table.Entries[idx] = []any{name, *index.DatasetSize, *index.DocsCount}
if idx == size-1 {
break
@@ -156,18 +156,18 @@ func IndexShow(conf *cfg.Config, indexpattern string) error {
created := time.Unix(ts/1000, 0)
- table.Entries = [][]string{
+ table.Entries = [][]any{
{"name", name},
{"replicas", *index.Settings.Index.NumberOfReplicas},
{"shards", *index.Settings.Index.NumberOfShards},
- {"created", created.Format("2006-01-02 15:04:05")},
+ {"created", created},
{"uuid", *index.Settings.Index.Uuid},
{"version", *index.Settings.Index.Version.Created},
- {"fields", strings.Join(fields, ",")},
+ {"fields", fields},
}
if index.Settings.Index.Lifecycle != nil {
- table.Entries = append(table.Entries, [][]string{
+ table.Entries = append(table.Entries, [][]any{
{"ilm policy", *index.Settings.Index.Lifecycle.Name},
{"ilm rollover alias", *index.Settings.Index.Lifecycle.RolloverAlias},
}...)
@@ -283,14 +283,14 @@ func IndexAllocation(conf *cfg.Config, index string) error {
roles[idx] = role.Name
}
- table.Entries = [][]string{
+ table.Entries = [][]any{
{"Index", index},
{"Current node", currentNode.Name},
{"Current k8s node", currentNode.Attributes["k8s_node_name"]},
{"Current node address", currentNode.TransportAddress},
{"Current node id", currentNode.Id},
- {"Current node weight", fmt.Sprintf("%d", currentNode.WeightRanking)},
- {"Current node roles", strings.Join(roles, ",")},
+ {"Current node weight", currentNode.WeightRanking},
+ {"Current node roles", roles},
{"Can rebalance cluster", res.CanRebalanceCluster.Name},
{"Can rebalance to another node", res.CanRebalanceToOtherNode.Name},
{"Can remain on current node", res.CanRemainOnCurrentNode.Name},
@@ -344,10 +344,11 @@ func IndexFields(conf *cfg.Config, index string) error {
continue
}
- table.Entries = append(table.Entries, []string{name, fieldtype,
- fmt.Sprintf("%t", caps.Searchable),
- fmt.Sprintf("%t", caps.Aggregatable),
- fmt.Sprintf("%t", *caps.MetadataField)})
+ table.AddRow(name, fieldtype,
+ caps.Searchable,
+ caps.Aggregatable,
+ *caps.MetadataField)
+
break
}
diff --git a/pkg/es/index_alias.go b/pkg/es/index_alias.go
index 0f0f49c..0745488 100644
--- a/pkg/es/index_alias.go
+++ b/pkg/es/index_alias.go
@@ -78,7 +78,7 @@ func IndexAliasList(conf *cfg.Config) error {
idx := 0
for index, aliases := range aliaslist {
- table.Entries[idx] = []string{
+ table.Entries[idx] = []any{
index,
strings.Join(aliases, ","),
}
@@ -117,10 +117,10 @@ func IndexAliasRollover(conf *cfg.Config, alias string) error {
table := printer.NewTable(conf, 2, 5)
table.Addheaders("rollover response", "value")
- table.Entries = [][]string{
- {"acknowledged", fmt.Sprintf("%t", res.Acknowledged)},
- {"rolled over", fmt.Sprintf("%t", res.RolledOver)},
- {"shards acknowledged", fmt.Sprintf("%t", res.ShardsAcknowledged)},
+ table.Entries = [][]any{
+ {"acknowledged", res.Acknowledged},
+ {"rolled over", res.RolledOver},
+ {"shards acknowledged", res.ShardsAcknowledged},
{"old index", res.OldIndex},
{"new index", res.NewIndex},
}
diff --git a/pkg/es/index_template.go b/pkg/es/index_template.go
index 85fcaa7..55a546f 100644
--- a/pkg/es/index_template.go
+++ b/pkg/es/index_template.go
@@ -51,11 +51,7 @@ func IndexTemplateList(conf *cfg.Config) error {
return fmt.Errorf("failed to unmarshal meta json data: %w", err)
}
- table.Entries[idx] = []string{
- tpl.Name,
- string(desc),
- fmt.Sprintf("%d", tpl.IndexTemplate.Priority),
- }
+ table.Entries[idx] = []any{tpl.Name, desc, tpl.IndexTemplate.Priority}
}
table.Sort()
@@ -94,13 +90,13 @@ func IndexTemplateShow(conf *cfg.Config, tplname string) error {
aliases = append(aliases, alias)
}
- table.Entries = [][]string{
+ table.Entries = [][]any{
{"name", tpl.Name},
- {"description", string(desc)},
- {"index patterns", strings.Join(tpl.IndexTemplate.IndexPatterns, ",")},
- {"composed of", strings.Join(tpl.IndexTemplate.ComposedOf, ",")},
- {"data stream enabled", fmt.Sprintf("%t", hasds)},
- {"aliases", strings.Join(aliases, ",")},
+ {"description", desc},
+ {"index patterns", tpl.IndexTemplate.IndexPatterns},
+ {"composed of", tpl.IndexTemplate.ComposedOf},
+ {"data stream enabled", hasds},
+ {"aliases", aliases},
}
if err := table.Print(); err != nil {
@@ -136,9 +132,7 @@ func IndexTemplateShow(conf *cfg.Config, tplname string) error {
typeval = val.Type
}
- table.Entries = append(table.Entries, []string{
- name, typeval,
- })
+ table.AddRow(name, typeval)
}
fmt.Println()
@@ -414,12 +408,7 @@ func rolloverAliasIndexTemplate(conf *cfg.Config, name string) error {
return err
}
- table.Entries = append(table.Entries, []string{
- alias,
- fmt.Sprintf("%t", res.RolledOver),
- fmt.Sprintf("%t", res.Acknowledged),
- res.NewIndex,
- })
+ table.AddRow(alias, res.RolledOver, res.Acknowledged, res.NewIndex)
if err := table.Print(); err != nil {
return err
diff --git a/pkg/es/index_template_settings.go b/pkg/es/index_template_settings.go
index 92df17c..d28da25 100644
--- a/pkg/es/index_template_settings.go
+++ b/pkg/es/index_template_settings.go
@@ -52,7 +52,7 @@ func getIndexTemplateSettings(conf *cfg.Config, tplname string, table *printer.T
tpl := data.IndexTemplates[0].IndexTemplate.Template.Settings
for topic, val := range tpl {
- table.Entries = append(table.Entries, []string{topic, fmt.Sprintf("%v", val)})
+ table.AddRow(topic, val)
}
return nil
diff --git a/pkg/es/license.go b/pkg/es/license.go
index 1d8eb63..cf74e1f 100644
--- a/pkg/es/license.go
+++ b/pkg/es/license.go
@@ -54,11 +54,11 @@ func LicenseShow(conf *cfg.Config) error {
maxunits = fmt.Sprintf("%d", *lic.MaxResourceUnits)
}
- table.Entries = [][]string{
+ table.Entries = [][]any{
{"UID", lic.Uid},
{"Issued to", lic.IssuedTo},
{"Expires", expire},
- {"Issued", lic.IssueDate.(string)},
+ {"Issued", lic.IssueDate},
{"Max nodes", maxnodes},
{"Max resource units", maxunits},
{"Type", lic.Type.Name},
diff --git a/pkg/es/node.go b/pkg/es/node.go
index d9874b8..bfa930c 100644
--- a/pkg/es/node.go
+++ b/pkg/es/node.go
@@ -41,14 +41,14 @@ func NodeList(conf *cfg.Config) error {
table.Addheaders("name", "ip", "load1m", "load5m", "load15m", "ram %", "heap %")
for idx, node := range nodes {
- table.Entries[idx] = []string{
+ table.Entries[idx] = []any{
*node.Name,
*node.Ip,
*node.Load1M,
*node.Load5M,
*node.Load15M,
- node.RamPercent.(string),
- node.HeapPercent.(string),
+ node.RamPercent,
+ node.HeapPercent,
}
}
@@ -113,25 +113,25 @@ func NodeShow(conf *cfg.Config, nodename string) error {
k8snode := info.Attributes["k8s_node_name"]
- table.Entries = [][]string{
+ table.Entries = [][]any{
{"Id", id},
{"Name", nodename},
{"Kubernetes node", k8snode},
{"Ip address", info.Ip},
{"Node rank", *stat.AdaptiveSelection[id].Rank},
{"JVM", info.Jvm.VmName + " " + info.Jvm.Version},
- {"JVM Started", time.UnixMilli(info.Jvm.StartTimeInMillis).String()},
+ {"JVM Started", time.UnixMilli(info.Jvm.StartTimeInMillis)},
{"OS", info.Os.PrettyName + " " + info.Os.Version},
- {"Node roles", strings.Join(roles, ",")},
+ {"Node roles", roles},
{"Node version", info.Version},
- {"HTTP clients", fmt.Sprintf("%d", *stat.Http.CurrentOpen)},
- {"CPUs", fmt.Sprintf("%d", *info.Os.AllocatedProcessors)},
+ {"HTTP clients", *stat.Http.CurrentOpen},
+ {"CPUs", *info.Os.AllocatedProcessors},
{"Load 15m/5m/1m", fmt.Sprintf("%.2f/%.2f/%.2f",
stat.Os.Cpu.LoadAverage["15m"],
stat.Os.Cpu.LoadAverage["5m"],
stat.Os.Cpu.LoadAverage["1m"],
)},
- {"Open FD's", fmt.Sprintf("%d", *stat.Process.OpenFileDescriptors)},
+ {"Open FD's", *stat.Process.OpenFileDescriptors},
{"Response time avg", fmt.Sprintf("%dns", *stat.AdaptiveSelection[id].AvgResponseTimeNs)},
{"Memory usage (used/avail)",
humanize.Bytes(uint64(*stat.Os.Mem.UsedInBytes)) + " / " + humanize.Bytes(uint64(*stat.Os.Mem.TotalInBytes))},
@@ -139,7 +139,7 @@ func NodeShow(conf *cfg.Config, nodename string) error {
if len(stat.Fs.Data) > 0 {
fs := stat.Fs.Data[0]
- table.Entries = append(table.Entries, [][]string{
+ table.Entries = append(table.Entries, [][]any{
{"Storage usage (used/avail)",
humanize.Bytes(uint64(*fs.AvailableInBytes)) + " / " + humanize.Bytes(uint64(*fs.TotalInBytes))},
{"Storage mount", *fs.Mount},
diff --git a/pkg/es/role.go b/pkg/es/role.go
index ffff478..357e1c1 100644
--- a/pkg/es/role.go
+++ b/pkg/es/role.go
@@ -20,7 +20,6 @@ import (
"context"
"fmt"
"log/slog"
- "strings"
"codeberg.org/scip/esctl/pkg/cfg"
"codeberg.org/scip/esctl/pkg/printer"
@@ -58,10 +57,10 @@ func RoleList(conf *cfg.Config) error {
idx := 0
for name, role := range res {
- table.Entries[idx] = []string{
+ table.Entries[idx] = []any{
name,
- fmt.Sprintf("%d", len(role.Cluster)),
- fmt.Sprintf("%d", len(role.Indices)),
+ role.Cluster,
+ role.Indices,
}
idx++
}
@@ -140,10 +139,8 @@ func roleRemoteClusters(conf *cfg.Config, role types.Role) error {
perms = append(perms, perm.Name)
}
- table.Entries[idx] = []string{
- strings.Join(priv.Clusters, ","),
- strings.Join(perms, ","),
- }
+ table.Entries[idx] = []any{priv.Clusters, perms}
+
idx++
}
@@ -160,7 +157,7 @@ func roleClusters(conf *cfg.Config, role types.Role) error {
table.Addheaders("cluster rights")
idx := 0
for _, cluster := range role.Cluster {
- table.Entries[idx] = []string{cluster.Name}
+ table.Entries[idx] = []any{cluster.Name}
idx++
}
@@ -182,11 +179,7 @@ func roleRemoteIndices(conf *cfg.Config, role types.Role) error {
perms = append(perms, perm.Name)
}
- table.Entries[idx] = []string{
- strings.Join(priv.Names, ", "),
- strings.Join(perms, ", "),
- fmt.Sprintf("%t", *priv.AllowRestrictedIndices),
- }
+ table.Entries[idx] = []any{priv.Names, perms, *priv.AllowRestrictedIndices}
idx++
}
@@ -209,11 +202,7 @@ func roleIndices(conf *cfg.Config, role types.Role) error {
perms = append(perms, perm.Name)
}
- table.Entries[idx] = []string{
- strings.Join(priv.Names, ", "),
- strings.Join(perms, ", "),
- fmt.Sprintf("%t", *priv.AllowRestrictedIndices),
- }
+ table.Entries[idx] = []any{priv.Names, perms, *priv.AllowRestrictedIndices}
idx++
}
@@ -231,10 +220,10 @@ func roleApplications(conf *cfg.Config, role types.Role) error {
table.Addheaders("application", "privileges", "resources")
idx := 0
for _, priv := range role.Applications {
- table.Entries[idx] = []string{
+ table.Entries[idx] = []any{
priv.Application,
- strings.Join(priv.Privileges, ", "),
- strings.Join(priv.Resources, ", "),
+ priv.Privileges,
+ priv.Resources,
}
idx++
diff --git a/pkg/es/role_diff.go b/pkg/es/role_diff.go
index bb5898c..838a5a8 100644
--- a/pkg/es/role_diff.go
+++ b/pkg/es/role_diff.go
@@ -229,7 +229,7 @@ func RoleDiff(conf *cfg.Config, csvfile, role string) error {
defined = printer.Colorize(conf, "red", "undefined")
}
- table.Entries[idx] = []string{
+ table.Entries[idx] = []any{
row.name,
deployed,
defined,
diff --git a/pkg/es/shard.go b/pkg/es/shard.go
index 24395fa..2e6de38 100644
--- a/pkg/es/shard.go
+++ b/pkg/es/shard.go
@@ -107,7 +107,7 @@ func printShards(conf *cfg.Config, shardlist shards.Response) error {
for idx, shard := range shardlist {
name := colorzizeShard(conf, *shard.State, *shard.Index)
- table.Entries[idx] = []string{
+ table.Entries[idx] = []any{
name,
*shard.Shard,
resolvePrirep(*shard.Prirep),
diff --git a/pkg/es/snapshot.go b/pkg/es/snapshot.go
index 2ef680c..b7144b9 100644
--- a/pkg/es/snapshot.go
+++ b/pkg/es/snapshot.go
@@ -88,7 +88,7 @@ func SnapshotList(conf *cfg.Config) error {
table.Addheaders("name", "index", "start", "orphaned", "status")
for idx, snap := range snapshots {
- table.Entries[idx] = []string{
+ table.Entries[idx] = []any{
snap.Name,
snap.Forindex,
snap.Start,
@@ -122,20 +122,20 @@ func SnapshotShow(conf *cfg.Config, snapshot string) error {
snap := res.Snapshots[0]
- table.Entries = [][]string{
+ table.Entries = [][]any{
{"snapshot", snapshot},
{"uuid", snap.Uuid},
{"repository", *snap.Repository},
- {"version_id", fmt.Sprintf("%d", snap.VersionId)},
+ {"version_id", snap.VersionId},
{"version", *snap.Version},
- {"include_global_state", fmt.Sprintf("%t", *snap.IncludeGlobalState)},
+ {"include_global_state", *snap.IncludeGlobalState},
{"state", *snap.State},
- {"start_time", fmt.Sprintf("%s", snap.StartTime)},
- {"end_time", fmt.Sprintf("%s", snap.EndTime)},
- {"duration_in_millis", fmt.Sprintf("%d", *snap.DurationInMillis)},
- {"shards-total", fmt.Sprintf("%d", snap.Shards.Total)},
- {"shards-failed", fmt.Sprintf("%d", snap.Shards.Failed)},
- {"shards-successful", fmt.Sprintf("%d", snap.Shards.Successful)},
+ {"start_time", snap.StartTime},
+ {"end_time", snap.EndTime},
+ {"duration_in_millis", *snap.DurationInMillis},
+ {"shards-total", snap.Shards.Total},
+ {"shards-failed", snap.Shards.Failed},
+ {"shards-successful", snap.Shards.Successful},
}
if err := table.Print(); err != nil {
diff --git a/pkg/es/task.go b/pkg/es/task.go
index 640bdb6..ebba906 100644
--- a/pkg/es/task.go
+++ b/pkg/es/task.go
@@ -49,10 +49,10 @@ func TaskList(conf *cfg.Config) error {
ts = time.Unix(int64(epc/1000), 0)
}
- table.Entries[idx] = []string{
+ table.Entries[idx] = []any{
*task.TaskId,
*task.Action,
- ts.Format("2006-01-02T15:04:05"),
+ ts,
*task.RunningTime,
*task.Node,
*task.Type,
diff --git a/pkg/printer/bytes.go b/pkg/printer/bytes.go
new file mode 100644
index 0000000..cae3c58
--- /dev/null
+++ b/pkg/printer/bytes.go
@@ -0,0 +1,31 @@
+/*
+Copyright © 2026 Thomas von Dein
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+package printer
+
+import "github.com/dustin/go-humanize"
+
+type ByteSize struct {
+ size uint64
+}
+
+func Bytes(size int64) ByteSize {
+ return ByteSize{size: uint64(size)}
+}
+
+func (b *ByteSize) String() string {
+ return humanize.Bytes(b.size)
+}
diff --git a/pkg/printer/cast.go b/pkg/printer/cast.go
new file mode 100644
index 0000000..40ad367
--- /dev/null
+++ b/pkg/printer/cast.go
@@ -0,0 +1,97 @@
+/*
+Copyright © 2026 Thomas von Dein
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+package printer
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/elastic/go-elasticsearch/v9/typedapi/types"
+)
+
+func any2string(in any) string {
+ switch val := in.(type) {
+ case string:
+ return val
+ case bool:
+ return strconv.FormatBool(val)
+ case int64:
+ return strconv.FormatInt(val, 10)
+ case int:
+ return strconv.Itoa(val)
+ case float64:
+ return fmt.Sprintf("%.2f", val)
+ case []string:
+ return strings.Join(val, ",")
+ case ByteSize:
+ return val.String()
+ case time.Time:
+ return val.Format("2006-01-02 15:04:05")
+ case []byte:
+ return string(val)
+ case types.DateTime, types.Percentage:
+ return val.(string)
+ case nil:
+ return "null"
+ }
+
+ return ""
+}
+
+func (data *Table) preprocessRows() {
+ if data.processed {
+ // only do it once
+ return
+ }
+
+ // convert entries to strings
+ data.rows = make([][]string, len(data.Entries))
+ for rowidx, entries := range data.Entries {
+ data.rows[rowidx] = make([]string, len(entries))
+
+ for colidx, entry := range data.Entries[rowidx] {
+ data.rows[rowidx][colidx] = any2string(entry)
+ }
+ }
+
+ // determine header lenght's
+ for idx, head := range data.Headers {
+ data.lenHeaders[idx] = visibleLen(head)
+ }
+
+ // determine max width per column
+ for _, entries := range data.rows {
+ currentWidth := 0
+ for idx, entry := range entries {
+ length := visibleLen(entry)
+
+ if data.lenHeaders[idx] < length {
+ if length > currentWidth+data.maxwidth {
+ data.lenHeaders[idx] = data.maxwidth - currentWidth
+ } else {
+ data.lenHeaders[idx] = length
+ }
+ }
+
+ currentWidth += data.lenHeaders[idx]
+ }
+ }
+
+ data.processed = true
+}
diff --git a/pkg/printer/table.go b/pkg/printer/table.go
index 363c97f..26020a2 100644
--- a/pkg/printer/table.go
+++ b/pkg/printer/table.go
@@ -25,18 +25,17 @@ import (
"strings"
"codeberg.org/scip/esctl/pkg/cfg"
- "github.com/olekukonko/tablewriter"
- "github.com/olekukonko/tablewriter/renderer"
- "github.com/olekukonko/tablewriter/tw"
"github.com/seeruk/go-wordwrap"
"gopkg.in/yaml.v3"
)
type Table struct {
- Mode string // table, markdown, json
+ Mode string // tsv, json, yaml
Headers []string
- Entries [][]string
+ Entries [][]any
+ rows [][]string // representation used for printing
+ processed bool
lenHeaders []int
alignInts bool
maxwidth int
@@ -46,7 +45,7 @@ func NewTable(conf *cfg.Config, columns, rows int) *Table {
table := Table{Mode: conf.Output, maxwidth: cfg.GetTermWidth()}
table.Headers = make([]string, columns)
- table.Entries = make([][]string, rows)
+ table.Entries = make([][]any, rows)
table.lenHeaders = make([]int, columns)
table.alignInts = conf.AlignInts
@@ -62,7 +61,7 @@ func NewTableEmpty(conf *cfg.Config) *Table {
func (table *Table) WithHeaders(headers ...string) *Table {
count := len(headers)
- table.Entries = [][]string{}
+ table.Entries = [][]any{}
table.lenHeaders = make([]int, count)
table.Headers = make([]string, count)
@@ -73,8 +72,6 @@ func (table *Table) WithHeaders(headers ...string) *Table {
func (data *Table) Print() error {
switch data.Mode {
- case "markdown", "md":
- return data.PrintMarkdown()
case "json":
return data.PrintJSON()
case "yaml":
@@ -89,11 +86,11 @@ var (
)
// needed for json and yaml output
-func (data *Table) toMap() []map[string]string {
- raw := make([]map[string]string, len(data.Entries))
+func (data *Table) toMap() []map[string]any {
+ raw := make([]map[string]any, len(data.Entries))
for idx, entries := range data.Entries {
- raw[idx] = make(map[string]string, len(data.Headers))
+ raw[idx] = make(map[string]any, len(data.Headers))
for eidx, entry := range entries {
raw[idx][data.Headers[eidx]] = entry
}
@@ -128,31 +125,9 @@ func (data *Table) PrintJSON() error {
return nil
}
-// Well. tablewriter should be able to print in TSV mode, but it
-// doesn't work because of the various ansic color escapes we're
-// using. Therefore we do it the hard way and use our own TSV printer.
func (data *Table) PrintTSV() error {
- // determine lenght's
- for idx, head := range data.Headers {
- data.lenHeaders[idx] = visibleLen(head)
- }
-
- for _, entries := range data.Entries {
- currentWidth := 0
- for idx, entry := range entries {
- length := visibleLen(entry)
-
- if data.lenHeaders[idx] < length {
- if length > currentWidth+data.maxwidth {
- data.lenHeaders[idx] = data.maxwidth - currentWidth
- } else {
- data.lenHeaders[idx] = length
- }
- }
-
- currentWidth += data.lenHeaders[idx]
- }
- }
+ // length's, convert cell types
+ data.preprocessRows()
// output headers
for idx, header := range data.Headers {
@@ -169,7 +144,7 @@ func (data *Table) PrintTSV() error {
}
fmt.Println()
- for _, entries := range data.Entries {
+ for _, entries := range data.rows {
currentWidth := 0
for idx, entry := range entries {
@@ -213,130 +188,16 @@ func (data *Table) PrintTSV() error {
return nil
}
-func (data *Table) PrintTabularFail() error {
- OFS := " "
-
- tableString := &strings.Builder{}
-
- styleTSV := tw.NewSymbolCustom("space").WithColumn("\t")
-
- table := tablewriter.NewTable(tableString,
- tablewriter.WithRenderer(
- renderer.NewBlueprint(tw.Rendition{
- Borders: tw.BorderNone,
- Symbols: styleTSV,
- Settings: tw.Settings{
- Separators: tw.SeparatorsNone,
- Lines: tw.LinesNone,
- },
- })),
- tablewriter.WithConfig(tablewriter.Config{
- Header: tw.CellConfig{
- Formatting: tw.CellFormatting{
- AutoFormat: tw.Off,
- },
- Padding: tw.CellPadding{Global: tw.Padding{Left: "", Right: OFS}},
- },
- Row: tw.CellConfig{
- Formatting: tw.CellFormatting{
- AutoWrap: tw.WrapNone,
- Alignment: tw.AlignLeft,
- },
- Padding: tw.CellPadding{Global: tw.Padding{Right: OFS}},
- },
-
- Debug: true,
- }),
- )
-
- table.Header(data.Headers)
-
- if err := table.Bulk(data.Entries); err != nil {
- return fmt.Errorf("failed to add data to table renderer: %s", err)
- }
-
- if err := table.Render(); err != nil {
- return fmt.Errorf("failed to render table: %s", err)
- }
-
- // we need to trim our output here, because tablewriter appends
- // excess whitespace to our rows.
- cleanedString := &strings.Builder{}
-
- for _, row := range strings.Split(strings.TrimSpace(tableString.String()), "\n") {
- cleanedString.WriteString(strings.TrimSpace(row))
- cleanedString.WriteString("\n")
- }
-
- fmt.Println(cleanedString.String())
-
- return nil
-}
-
-func (data *Table) PrintMarkdown() error {
- tableString := &strings.Builder{}
-
- table := tablewriter.NewTable(tableString,
- tablewriter.WithRenderer(
- renderer.NewBlueprint(
- tw.Rendition{
- Borders: tw.Border{
- Left: tw.On,
- Right: tw.On,
- Top: tw.Off,
- Bottom: tw.Off,
- },
- Settings: tw.Settings{
- Separators: tw.Separators{
- ShowHeader: tw.On,
- ShowFooter: tw.Off,
- BetweenRows: tw.Off,
- BetweenColumns: 0,
- },
- },
- Symbols: tw.NewSymbols(tw.StyleMarkdown),
- })),
-
- tablewriter.WithConfig(
- tablewriter.Config{
- Header: tw.CellConfig{
- Formatting: tw.CellFormatting{
- Alignment: tw.AlignLeft,
- AutoFormat: tw.Off,
- },
- },
- Row: tw.CellConfig{
- Formatting: tw.CellFormatting{
- Alignment: tw.AlignLeft,
- },
- },
- },
- ),
- )
-
- table.Header(data.Headers)
-
- if err := table.Bulk(data.Entries); err != nil {
- return fmt.Errorf("failed to add data to table renderer: %s", err)
- }
-
- if err := table.Render(); err != nil {
- return fmt.Errorf("failed to render table: %s", err)
- }
-
- fmt.Println(tableString.String())
-
- return nil
-}
-
func (data *Table) Sort() {
// sanity checks
if len(data.Entries) == 0 {
return
}
- sort.Slice(data.Entries, func(i, j int) bool {
- return data.Entries[i][0] < data.Entries[j][0]
+ data.preprocessRows()
+
+ sort.Slice(data.rows, func(i, j int) bool {
+ return data.rows[i][0] < data.rows[j][0]
})
}
@@ -351,7 +212,7 @@ func (data *Table) Addheaders(headers ...string) {
}
}
-func (data *Table) AddRow(fields ...string) {
+func (data *Table) AddRow(fields ...any) {
data.Entries = append(data.Entries, fields)
}