mirror of
https://codeberg.org/scip/esctl.git
synced 2026-08-24 12:44:18 +02:00
Compare commits
6 Commits
enhance/go
...
mapper
| Author | SHA1 | Date | |
|---|---|---|---|
| 17e61a151a | |||
| ab0b3ad7ab | |||
| e423e448e7 | |||
|
|
55a1005857 | ||
|
|
2f13e08536 | ||
|
|
97a509da9e |
@@ -34,6 +34,7 @@ const (
|
|||||||
Cilm
|
Cilm
|
||||||
Cnode
|
Cnode
|
||||||
Cclustersettings
|
Cclustersettings
|
||||||
|
Cindextemplate
|
||||||
)
|
)
|
||||||
|
|
||||||
func complete(conf *cfg.Config, cmd *cli.Command, what int) {
|
func complete(conf *cfg.Config, cmd *cli.Command, what int) {
|
||||||
@@ -65,6 +66,8 @@ func complete(conf *cfg.Config, cmd *cli.Command, what int) {
|
|||||||
list, err = es.NodeNames(conf)
|
list, err = es.NodeNames(conf)
|
||||||
case Cclustersettings:
|
case Cclustersettings:
|
||||||
list, err = es.ClusterSettingsNames(conf)
|
list, err = es.ClusterSettingsNames(conf)
|
||||||
|
case Cindextemplate:
|
||||||
|
list, err = es.IndexTemplateNames(conf)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -49,8 +49,23 @@ func IndexTemplateList(conf *cfg.Config) *cli.Command {
|
|||||||
Aliases: []string{"ls"},
|
Aliases: []string{"ls"},
|
||||||
Usage: "list index templates",
|
Usage: "list index templates",
|
||||||
|
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringSliceFlag{
|
||||||
|
Name: "filter-index-pattern",
|
||||||
|
Usage: "show only index templates which use patterns, which match the filter",
|
||||||
|
Destination: &conf.Filter,
|
||||||
|
Aliases: []string{"F"},
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "hidden",
|
||||||
|
Usage: "show hidden index templates as well",
|
||||||
|
Destination: &conf.Hidden,
|
||||||
|
Aliases: []string{"H"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||||
return es.IndexTemplateList(conf)
|
return es.IndexTemplateList(conf, cmd.Args().Get(0))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -71,7 +86,7 @@ func IndexTemplateShow(conf *cfg.Config) *cli.Command {
|
|||||||
},
|
},
|
||||||
|
|
||||||
ShellComplete: func(ctx context.Context, cmd *cli.Command) {
|
ShellComplete: func(ctx context.Context, cmd *cli.Command) {
|
||||||
complete(conf, cmd, Cindex)
|
complete(conf, cmd, Cindextemplate)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -215,7 +230,7 @@ func IndexTemplateDelete(conf *cfg.Config) *cli.Command {
|
|||||||
},
|
},
|
||||||
|
|
||||||
ShellComplete: func(ctx context.Context, cmd *cli.Command) {
|
ShellComplete: func(ctx context.Context, cmd *cli.Command) {
|
||||||
complete(conf, cmd, Cindex)
|
complete(conf, cmd, Cindextemplate)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
3
go.mod
3
go.mod
@@ -18,7 +18,7 @@ go 1.26
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/MichaelMure/go-term-markdown v0.1.4
|
github.com/MichaelMure/go-term-markdown v0.1.4
|
||||||
github.com/alecthomas/repr v0.5.2
|
github.com/alecthomas/repr v0.5.3
|
||||||
github.com/charmbracelet/bubbles v1.0.0
|
github.com/charmbracelet/bubbles v1.0.0
|
||||||
github.com/charmbracelet/bubbletea v1.3.10
|
github.com/charmbracelet/bubbletea v1.3.10
|
||||||
github.com/charmbracelet/lipgloss v1.1.0
|
github.com/charmbracelet/lipgloss v1.1.0
|
||||||
@@ -40,6 +40,7 @@ require (
|
|||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
codeberg.org/scip/mapmap v0.0.2 // indirect
|
||||||
github.com/MichaelMure/go-term-text v0.3.1 // indirect
|
github.com/MichaelMure/go-term-text v0.3.1 // indirect
|
||||||
github.com/alecthomas/chroma v0.7.1 // indirect
|
github.com/alecthomas/chroma v0.7.1 // indirect
|
||||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||||
|
|||||||
8
go.sum
8
go.sum
@@ -1,3 +1,7 @@
|
|||||||
|
codeberg.org/scip/mapmap v0.0.1 h1:L1jMBo/UNp19MXUF/ONjc1XKVGeuF1x05z0pEhjgkzA=
|
||||||
|
codeberg.org/scip/mapmap v0.0.1/go.mod h1:/ojYo2P7dMA2FWEu+jHKmsKPeq5yDcCvXeHevqZd5OI=
|
||||||
|
codeberg.org/scip/mapmap v0.0.2 h1:0i61jOUwFmGVwPukrMzrx0Fi4T9Qru2nlmibuaJimBo=
|
||||||
|
codeberg.org/scip/mapmap v0.0.2/go.mod h1:/ojYo2P7dMA2FWEu+jHKmsKPeq5yDcCvXeHevqZd5OI=
|
||||||
github.com/MichaelMure/go-term-markdown v0.1.4 h1:Ir3kBXDUtOX7dEv0EaQV8CNPpH+T7AfTh0eniMOtNcs=
|
github.com/MichaelMure/go-term-markdown v0.1.4 h1:Ir3kBXDUtOX7dEv0EaQV8CNPpH+T7AfTh0eniMOtNcs=
|
||||||
github.com/MichaelMure/go-term-markdown v0.1.4/go.mod h1:EhcA3+pKYnlUsxYKBJ5Sn1cTQmmBMjeNlpV8nRb+JxA=
|
github.com/MichaelMure/go-term-markdown v0.1.4/go.mod h1:EhcA3+pKYnlUsxYKBJ5Sn1cTQmmBMjeNlpV8nRb+JxA=
|
||||||
github.com/MichaelMure/go-term-text v0.3.1 h1:Kw9kZanyZWiCHOYu9v/8pWEgDQ6UVN9/ix2Vd2zzWf0=
|
github.com/MichaelMure/go-term-text v0.3.1 h1:Kw9kZanyZWiCHOYu9v/8pWEgDQ6UVN9/ix2Vd2zzWf0=
|
||||||
@@ -10,8 +14,8 @@ github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721 h1:JHZL0hZKJ1VEN
|
|||||||
github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0=
|
github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0=
|
||||||
github.com/alecthomas/kong v0.2.1-0.20190708041108-0548c6b1afae/go.mod h1:+inYUSluD+p4L8KdviBSgzcqEjUQOfC5fQDRFuc36lI=
|
github.com/alecthomas/kong v0.2.1-0.20190708041108-0548c6b1afae/go.mod h1:+inYUSluD+p4L8KdviBSgzcqEjUQOfC5fQDRFuc36lI=
|
||||||
github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ=
|
github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ=
|
||||||
github.com/alecthomas/repr v0.5.2 h1:SU73FTI9D1P5UNtvseffFSGmdNci/O6RsqzeXJtP0Qs=
|
github.com/alecthomas/repr v0.5.3 h1:Ebk3yZ0kvrHC7TkTHLDJGDq1LxKeu9sQBQREFMcesS8=
|
||||||
github.com/alecthomas/repr v0.5.2/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
|
github.com/alecthomas/repr v0.5.3/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 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
|
||||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
||||||
github.com/charmbracelet/bubbles v1.0.0 h1:12J8/ak/uCZEMQ6KU7pcfwceyjLlWsDLAxB5fXonfvc=
|
github.com/charmbracelet/bubbles v1.0.0 h1:12J8/ak/uCZEMQ6KU7pcfwceyjLlWsDLAxB5fXonfvc=
|
||||||
|
|||||||
@@ -30,9 +30,11 @@ import (
|
|||||||
|
|
||||||
"codeberg.org/scip/esctl/pkg/cfg"
|
"codeberg.org/scip/esctl/pkg/cfg"
|
||||||
"codeberg.org/scip/esctl/pkg/printer"
|
"codeberg.org/scip/esctl/pkg/printer"
|
||||||
|
"codeberg.org/scip/mapmap"
|
||||||
"github.com/charmbracelet/lipgloss"
|
"github.com/charmbracelet/lipgloss"
|
||||||
"github.com/elastic/go-elasticsearch/v9/typedapi/cat/indices"
|
"github.com/elastic/go-elasticsearch/v9/typedapi/cat/indices"
|
||||||
"github.com/elastic/go-elasticsearch/v9/typedapi/esdsl"
|
"github.com/elastic/go-elasticsearch/v9/typedapi/esdsl"
|
||||||
|
"github.com/elastic/go-elasticsearch/v9/typedapi/types"
|
||||||
"github.com/elastic/go-elasticsearch/v9/typedapi/types/enums/healthstatus"
|
"github.com/elastic/go-elasticsearch/v9/typedapi/types/enums/healthstatus"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -53,41 +55,34 @@ func IndexNames(conf *cfg.Config) ([]string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func filterIndices(conf *cfg.Config, list indices.Response) indices.Response {
|
func filterIndices(conf *cfg.Config, list indices.Response) indices.Response {
|
||||||
// apply partials filter first
|
var filter *regexp.Regexp
|
||||||
selectedlist := indices.Response{}
|
|
||||||
|
if len(conf.Filter) > 0 {
|
||||||
|
filter = regexp.MustCompile(conf.Filter[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
return mapmap.NewSlicer(list).MapSliceValuesImmutable(func(index types.IndicesRecord) bool {
|
||||||
|
if strings.HasPrefix(*index.Index, ".ds-") {
|
||||||
|
// ignore data stream backing indicies
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
for _, index := range list {
|
|
||||||
if !conf.Partials && strings.HasPrefix(*index.Index, "partial-") {
|
if !conf.Partials && strings.HasPrefix(*index.Index, "partial-") {
|
||||||
continue
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if !conf.Hidden && strings.HasPrefix(*index.Index, ".") {
|
if !conf.Hidden && strings.HasPrefix(*index.Index, ".") {
|
||||||
continue
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.HasPrefix(*index.Index, ".ds-") {
|
if len(conf.Filter) > 0 {
|
||||||
// ignore data stream backing indicies
|
if !filter.MatchString(*index.Index) {
|
||||||
continue
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
selectedlist = append(selectedlist, index)
|
return true
|
||||||
}
|
})
|
||||||
|
|
||||||
if len(conf.Filter) == 0 {
|
|
||||||
return selectedlist
|
|
||||||
}
|
|
||||||
|
|
||||||
// we support just one filter here, for now
|
|
||||||
filter := *regexp.MustCompile(conf.Filter[0])
|
|
||||||
newlist := indices.Response{}
|
|
||||||
|
|
||||||
for _, index := range selectedlist {
|
|
||||||
if filter.MatchString(*index.Index) {
|
|
||||||
newlist = append(newlist, index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return newlist
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func IndexList(conf *cfg.Config) error {
|
func IndexList(conf *cfg.Config) error {
|
||||||
|
|||||||
@@ -28,12 +28,29 @@ import (
|
|||||||
|
|
||||||
"codeberg.org/scip/esctl/pkg/cfg"
|
"codeberg.org/scip/esctl/pkg/cfg"
|
||||||
"codeberg.org/scip/esctl/pkg/printer"
|
"codeberg.org/scip/esctl/pkg/printer"
|
||||||
|
"codeberg.org/scip/mapmap"
|
||||||
"github.com/elastic/go-elasticsearch/v9/typedapi/esdsl"
|
"github.com/elastic/go-elasticsearch/v9/typedapi/esdsl"
|
||||||
"github.com/elastic/go-elasticsearch/v9/typedapi/types"
|
"github.com/elastic/go-elasticsearch/v9/typedapi/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// used for completion
|
// used for completion
|
||||||
func IndexTemplateList(conf *cfg.Config) error {
|
func IndexTemplateNames(conf *cfg.Config) ([]string, error) {
|
||||||
|
res, err := conf.DefaultCluster.ES().Indices.GetIndexTemplate().
|
||||||
|
Do(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get index templates: %w", esErrorString(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
names := make([]string, len(res.IndexTemplates))
|
||||||
|
|
||||||
|
for idx, tpl := range res.IndexTemplates {
|
||||||
|
names[idx] = tpl.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
return names, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func IndexTemplateList(conf *cfg.Config, filter string) error {
|
||||||
res, err := conf.DefaultCluster.ES().Indices.GetIndexTemplate().
|
res, err := conf.DefaultCluster.ES().Indices.GetIndexTemplate().
|
||||||
Do(context.Background())
|
Do(context.Background())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -42,16 +59,20 @@ func IndexTemplateList(conf *cfg.Config) error {
|
|||||||
|
|
||||||
slog.Debug("res", "index templates", res)
|
slog.Debug("res", "index templates", res)
|
||||||
|
|
||||||
table := printer.NewTable(conf, 5, len(res.IndexTemplates))
|
table := printer.NewTable(conf, 5, 0)
|
||||||
table.Addheaders("name", "description", "priority")
|
table.Addheaders("name", "description", "index patterns", "priority")
|
||||||
|
|
||||||
for idx, tpl := range res.IndexTemplates {
|
tplList := filterIndexTemplates(conf, filter, res.IndexTemplates)
|
||||||
desc, err := json.Marshal(tpl.IndexTemplate.Meta_["description"])
|
|
||||||
if err != nil {
|
for _, tpl := range tplList {
|
||||||
return fmt.Errorf("failed to unmarshal meta json data: %w", err)
|
desc := strings.TrimPrefix(strings.TrimSuffix(string(tpl.IndexTemplate.Meta_["description"]), `"`), `"`)
|
||||||
|
|
||||||
|
var prio int64
|
||||||
|
if tpl.IndexTemplate.Priority != nil {
|
||||||
|
prio = *tpl.IndexTemplate.Priority
|
||||||
}
|
}
|
||||||
|
|
||||||
table.Entries[idx] = []any{tpl.Name, desc, tpl.IndexTemplate.Priority}
|
table.AddRow(tpl.Name, desc, tpl.IndexTemplate.IndexPatterns, prio)
|
||||||
}
|
}
|
||||||
|
|
||||||
table.Sort()
|
table.Sort()
|
||||||
@@ -59,6 +80,30 @@ func IndexTemplateList(conf *cfg.Config) error {
|
|||||||
return table.Print()
|
return table.Print()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Filter index templates by name, index pattern or hidden flag, using
|
||||||
|
// mapmap.Slicer
|
||||||
|
func filterIndexTemplates(conf *cfg.Config, nameFilter string,
|
||||||
|
templates []types.IndexTemplateItem) []types.IndexTemplateItem {
|
||||||
|
return mapmap.NewSlicer(templates).MapSliceValuesImmutable(func(tpl types.IndexTemplateItem) bool {
|
||||||
|
if !conf.Hidden && strings.HasPrefix(tpl.Name, ".") {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if nameFilter != "" && !strings.Contains(tpl.Name, nameFilter) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(conf.Filter) > 0 {
|
||||||
|
if !mapmap.NewSlicer(tpl.IndexTemplate.IndexPatterns).
|
||||||
|
FindSliceInSlice(conf.Filter, strings.Contains) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func IndexTemplateShow(conf *cfg.Config, tplname string) error {
|
func IndexTemplateShow(conf *cfg.Config, tplname string) error {
|
||||||
res, err := conf.DefaultCluster.ES().Indices.GetIndexTemplate().
|
res, err := conf.DefaultCluster.ES().Indices.GetIndexTemplate().
|
||||||
Name(tplname).
|
Name(tplname).
|
||||||
|
|||||||
55
pkg/printer/metrics.go
Normal file
55
pkg/printer/metrics.go
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package printer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"runtime/metrics"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func printGoRoutineMetrics() {
|
||||||
|
fmt.Println("\nGoroutine metrics:")
|
||||||
|
printMetric("/sched/goroutines-created:goroutines", "Created")
|
||||||
|
printMetric("/sched/goroutines:goroutines", "Live")
|
||||||
|
printMetric("/sched/goroutines/not-in-go:goroutines", "Syscall/CGO")
|
||||||
|
printMetric("/sched/goroutines/runnable:goroutines", "Runnable")
|
||||||
|
printMetric("/sched/goroutines/running:goroutines", "Running")
|
||||||
|
printMetric("/sched/goroutines/waiting:goroutines", "Waiting")
|
||||||
|
|
||||||
|
fmt.Println("Thread metrics:")
|
||||||
|
printMetric("/sched/gomaxprocs:threads", "Max")
|
||||||
|
printMetric("/sched/threads/total:threads", "Live")
|
||||||
|
}
|
||||||
|
|
||||||
|
func printMetric(name string, descr string) {
|
||||||
|
sample := []metrics.Sample{{Name: name}}
|
||||||
|
metrics.Read(sample)
|
||||||
|
|
||||||
|
var val string
|
||||||
|
|
||||||
|
switch sample[0].Value.Kind() {
|
||||||
|
case metrics.KindFloat64, metrics.KindFloat64Histogram:
|
||||||
|
val = fmt.Sprintf("%.2f", sample[0].Value.Float64())
|
||||||
|
case metrics.KindUint64:
|
||||||
|
val = strconv.FormatUint(sample[0].Value.Uint64(), 10)
|
||||||
|
case metrics.KindBad:
|
||||||
|
val = "n/a"
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf(" %s: %v\n", descr, val)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user