From 231b0d03fed93ccc4b5f953f503763966341ec48 Mon Sep 17 00:00:00 2001 From: "Sean E. Russell" Date: Fri, 28 Feb 2020 10:03:41 -0600 Subject: Extensions. --- cmd/gotop/main.go | 64 +++++++++++++++++++++++++++++++++++++-- colorschemes/default.go | 3 +- colorschemes/default.json | 3 +- colorschemes/default_dark.go | 3 +- colorschemes/monokai.go | 3 +- colorschemes/nord.go | 3 +- colorschemes/solarized.go | 3 +- colorschemes/solarized16_dark.go | 3 +- colorschemes/solarized16_light.go | 3 +- colorschemes/template.go | 3 +- colorschemes/vice.go | 3 +- config.go | 3 ++ devices/cpu.go | 6 ++-- devices/cpu_cpu.go | 4 +-- layout/layout.go | 11 +++++-- widgets/cpu.go | 20 ++++++------ widgets/mem.go | 5 ++- 17 files changed, 102 insertions(+), 41 deletions(-) diff --git a/cmd/gotop/main.go b/cmd/gotop/main.go index 274cf29..0fae9e2 100644 --- a/cmd/gotop/main.go +++ b/cmd/gotop/main.go @@ -8,6 +8,7 @@ import ( "os" "os/signal" "path/filepath" + "plugin" "strconv" "strings" "syscall" @@ -33,6 +34,7 @@ const ( defaultUI = "cpu\ndisk/1 2:mem/2\ntemp\nnet procs" minimalUI = "cpu\nmem procs" batteryUI = "cpu/2 batt/1\ndisk/1 2:mem/2\ntemp\nnet procs" + procsUI = "cpu 4:procs\ndisk\nmem\nnet" ) var ( @@ -65,12 +67,16 @@ Options: -b, --battery Show battery level widget ('minimal' turns off). (DEPRECATED, use -l battery) -B, --bandwidth=bits Specify the number of bits per seconds. -l, --layout=NAME Name of layout spec file for the UI. Looks first in $XDG_CONFIG_HOME/gotop, then as a path. Use "-" to pipe. - -i, --interface=NAME Select network interface [default: all]. + -i, --interface=NAME Select network interface [default: all]. Several interfaces can be defined using comma separated values. Interfaces can also be ignored using ! -x, --export=PORT Enable metrics for export on the specified port. + -X, --extensions=NAMES Enables the listed extensions. This is a comma-separated list without the .so suffix. The current and config directories will be searched. -Several interfaces can be defined using comma separated values. -Interfaces can also be ignored using ! +Built-in layouts: + default + minimal + battery + kitchensink Colorschemes: default @@ -142,6 +148,10 @@ Colorschemes: if val, _ := args["--interface"]; val != nil { conf.NetInterface, _ = args["--interface"].(string) } + if val, _ := args["--extensions"]; val != nil { + exs, _ := args["--extensions"].(string) + conf.Extensions = strings.Split(exs, ",") + } return nil } @@ -386,6 +396,8 @@ func main() { bar = w.NewStatusBar() } + loadExtensions(conf) + lstream := getLayout(conf) ly := layout.ParseLayout(lstream) grid, err := layout.Layout(ly, conf) @@ -426,6 +438,8 @@ func getLayout(conf gotop.Config) io.Reader { return strings.NewReader(minimalUI) case "battery": return strings.NewReader(batteryUI) + case "procs": + return strings.NewReader(procsUI) default: fp := filepath.Join(conf.ConfigDir, conf.Layout) fin, err := os.Open(fp) @@ -438,3 +452,47 @@ func getLayout(conf gotop.Config) io.Reader { return fin } } + +func loadExtensions(conf gotop.Config) { + var hasError bool + for _, ex := range conf.Extensions { + exf := ex + ".so" + fn := exf + _, err := os.Stat(fn) + if err != nil && os.IsNotExist(err) { + log.Printf("no plugin %s found in current directory", fn) + fn = filepath.Join(conf.ConfigDir, exf) + _, err = os.Stat(fn) + if err != nil || os.IsNotExist(err) { + hasError = true + log.Printf("no plugin %s found in config directory", fn) + continue + } + } + p, err := plugin.Open(fn) + if err != nil { + hasError = true + log.Printf(err.Error()) + continue + } + init, err := p.Lookup("Init") + if err != nil { + hasError = true + log.Printf(err.Error()) + continue + } + + initFunc, ok := init.(func()) + if !ok { + hasError = true + log.Printf(err.Error()) + continue + } + initFunc() + } + if hasError { + ui.Close() + fmt.Printf("Error initializing requested plugins; check the log file %s\n", filepath.Join(conf.ConfigDir, conf.LogFile)) + os.Exit(1) + } +} diff --git a/colorschemes/default.go b/colorschemes/default.go index dc6c6b2..90ac3fa 100644 --- a/colorschemes/default.go +++ b/colorschemes/default.go @@ -12,8 +12,7 @@ func init() { BattLines: []int{4, 3, 2, 1, 5, 6, 7, 8}, - MainMem: 5, - SwapMem: 11, + MemLines: []int{5, 11, 4, 3, 2, 1, 6, 7, 8}, ProcCursor: 4, diff --git a/colorschemes/default.json b/colorschemes/default.json index 12cab1b..d6b3dc5 100644 --- a/colorschemes/default.json +++ b/colorschemes/default.json @@ -11,8 +11,7 @@ "BattLines": [4, 3, 2, 1, 5, 6, 7, 8], - "MainMem": 5, - "SwapMem": 11, + "MemLines": [5, 11, 4, 3, 2, 1, 6, 7, 8], "ProcCursor": 4, diff --git a/colorschemes/default_dark.go b/colorschemes/default_dark.go index 849f85b..7f7911c 100644 --- a/colorschemes/default_dark.go +++ b/colorschemes/default_dark.go @@ -12,8 +12,7 @@ func init() { BattLines: []int{4, 3, 2, 1, 5, 6, 7, 8}, - MainMem: 5, - SwapMem: 3, + MemLines: []int{5, 3, 4, 2, 1, 6, 7, 8, 11}, ProcCursor: 33, diff --git a/colorschemes/monokai.go b/colorschemes/monokai.go index cd0471c..d09f3c9 100644 --- a/colorschemes/monokai.go +++ b/colorschemes/monokai.go @@ -12,8 +12,7 @@ func init() { BattLines: []int{81, 70, 208, 197, 249, 141, 221, 186}, - MainMem: 208, - SwapMem: 186, + MemLines: []int{208, 186, 81, 70, 208, 197, 249, 141, 221, 186}, ProcCursor: 197, diff --git a/colorschemes/nord.go b/colorschemes/nord.go index b6d4b50..028057e 100644 --- a/colorschemes/nord.go +++ b/colorschemes/nord.go @@ -25,8 +25,7 @@ func init() { BattLines: []int{4, 3, 2, 1, 5, 6, 7, 8}, - MainMem: 172, // Orange - SwapMem: 221, // yellow + MemLines: []int{172, 221, 4, 3, 2, 1, 5, 6, 7, 8}, ProcCursor: 31, // blue (nord9) diff --git a/colorschemes/solarized.go b/colorschemes/solarized.go index 48d67b0..4649d93 100644 --- a/colorschemes/solarized.go +++ b/colorschemes/solarized.go @@ -15,8 +15,7 @@ func init() { BattLines: []int{61, 33, 37, 64, 125, 160, 166, 136}, - MainMem: 125, - SwapMem: 166, + MemLines: []int{125, 166, 61, 33, 37, 64, 125, 160, 166, 136}, ProcCursor: 136, diff --git a/colorschemes/solarized16_dark.go b/colorschemes/solarized16_dark.go index 354991b..00c7eb6 100644 --- a/colorschemes/solarized16_dark.go +++ b/colorschemes/solarized16_dark.go @@ -14,8 +14,7 @@ func init() { BattLines: []int{13, 4, 6, 2, 5, 1, 9, 3}, - MainMem: 5, - SwapMem: 9, + MemLines: []int{5, 9, 13, 4, 6, 2, 1, 3}, ProcCursor: 4, diff --git a/colorschemes/solarized16_light.go b/colorschemes/solarized16_light.go index 0fae397..b4157d9 100644 --- a/colorschemes/solarized16_light.go +++ b/colorschemes/solarized16_light.go @@ -14,8 +14,7 @@ func init() { BattLines: []int{13, 4, 6, 2, 5, 1, 9, 3}, - MainMem: 5, - SwapMem: 9, + MemLines: []int{5, 9, 13, 4, 6, 2, 1, 3}, ProcCursor: 4, diff --git a/colorschemes/template.go b/colorschemes/template.go index 9b7ac79..af4b792 100644 --- a/colorschemes/template.go +++ b/colorschemes/template.go @@ -32,8 +32,7 @@ type Colorscheme struct { BattLines []int - MainMem int - SwapMem int + MemLines []int ProcCursor int diff --git a/colorschemes/vice.go b/colorschemes/vice.go index 8bd2545..d0dbb03 100644 --- a/colorschemes/vice.go +++ b/colorschemes/vice.go @@ -12,8 +12,7 @@ func init() { BattLines: []int{212, 218, 123, 159, 229, 158, 183, 146}, - MainMem: 201, - SwapMem: 97, + MemLines: []int{201, 97, 212, 218, 123, 159, 229, 158, 183, 146}, ProcCursor: 159, diff --git a/config.go b/config.go index fc6e521..9109a4b 100644 --- a/config.go +++ b/config.go @@ -31,6 +31,7 @@ type Config struct { Layout string MaxLogSize int64 ExportPort string + Extensions []string } func Parse(in io.Reader, conf *Config) error { @@ -112,6 +113,8 @@ func Parse(in io.Reader, conf *Config) error { conf.MaxLogSize = int64(iv) case "export": conf.ExportPort = kv[1] + case "extensions": + conf.Extensions = strings.Split(kv[1], ",") } } diff --git a/devices/cpu.go b/devices/cpu.go index 21d21b6..436ccb1 100644 --- a/devices/cpu.go +++ b/devices/cpu.go @@ -5,7 +5,7 @@ import ( "time" ) -var cpuFuncs []func(map[string]float64, time.Duration, bool) map[string]error +var cpuFuncs []func(map[string]int, time.Duration, bool) map[string]error // RegisterCPU adds a new CPU device to the CPU widget. labels returns the // names of the devices; they should be as short as possible, and the indexes @@ -16,13 +16,13 @@ var cpuFuncs []func(map[string]float64, time.Duration, bool) map[string]error // // labels may be called once and the value cached. This means the number of // cores should not change dynamically. -func RegisterCPU(f func(map[string]float64, time.Duration, bool) map[string]error) { +func RegisterCPU(f func(map[string]int, time.Duration, bool) map[string]error) { cpuFuncs = append(cpuFuncs, f) } // CPUPercent calculates the percentage of cpu used either per CPU or combined. // Returns one value per cpu, or a single value if percpu is set to false. -func UpdateCPU(cpus map[string]float64, interval time.Duration, logical bool) { +func UpdateCPU(cpus map[string]int, interval time.Duration, logical bool) { for _, f := range cpuFuncs { errs := f(cpus, interval, logical) if errs != nil { diff --git a/devices/cpu_cpu.go b/devices/cpu_cpu.go index e18b51d..a1d20cd 100644 --- a/devices/cpu_cpu.go +++ b/devices/cpu_cpu.go @@ -8,7 +8,7 @@ import ( ) func init() { - f := func(cpus map[string]float64, iv time.Duration, l bool) map[string]error { + f := func(cpus map[string]int, iv time.Duration, l bool) map[string]error { cpuCount, err := psCpu.Counts(l) if err != nil { return nil @@ -23,7 +23,7 @@ func init() { } for i := 0; i < len(vals); i++ { key := fmt.Sprintf(formatString, i) - cpus[key] = vals[i] + cpus[key] = int(vals[i]) } return nil } diff --git a/layout/layout.go b/layout/layout.go index 12bc5d2..bdddaf6 100644 --- a/layout/layout.go +++ b/layout/layout.go @@ -168,8 +168,15 @@ func makeWidget(c gotop.Config, widRule widgetRule) interface{} { w = dw case "mem": m := widgets.NewMemWidget(c.UpdateInterval, c.GraphHorizontalScale) - m.LineColors["Main"] = ui.Color(c.Colorscheme.MainMem) - m.LineColors["Swap"] = ui.Color(c.Colorscheme.SwapMem) + var i int + for key, _ := range m.Data { + if i >= len(c.Colorscheme.MemLines) { + i = 0 + } + color := c.Colorscheme.MemLines[i] + m.LineColors[key] = ui.Color(color) + i++ + } w = m case "temp": t := widgets.NewTempWidget(c.TempScale) diff --git a/widgets/cpu.go b/widgets/cpu.go index e56cd3d..53f5529 100644 --- a/widgets/cpu.go +++ b/widgets/cpu.go @@ -48,10 +48,10 @@ func NewCpuWidget(updateInterval time.Duration, horizontalScale int, showAverage } if self.ShowPerCpuLoad { - cpus := make(map[string]float64) + cpus := make(map[string]int) devices.UpdateCPU(cpus, self.updateInterval, self.ShowPerCpuLoad) for k, v := range cpus { - self.Data[k] = []float64{v} + self.Data[k] = []float64{float64(v)} } } @@ -74,7 +74,7 @@ func (self *CpuWidget) EnableMetric() { Name: "avg", }) } else { - cpus := make(map[string]float64) + cpus := make(map[string]int) devices.UpdateCPU(cpus, self.updateInterval, self.ShowPerCpuLoad) self.metric = make(map[string]prometheus.Gauge) for key, perc := range cpus { @@ -83,7 +83,7 @@ func (self *CpuWidget) EnableMetric() { Subsystem: "cpu", Name: key, }) - gauge.Set(perc) + gauge.Set(float64(perc)) prometheus.MustRegister(gauge) self.metric[key] = gauge } @@ -97,7 +97,7 @@ func (b *CpuWidget) Scale(i int) { func (self *CpuWidget) update() { if self.ShowAverageLoad { go func() { - cpus := make(map[string]float64) + cpus := make(map[string]int) devices.UpdateCPU(cpus, self.updateInterval, false) self.Lock() defer self.Unlock() @@ -105,7 +105,7 @@ func (self *CpuWidget) update() { defer self.updateLock.Unlock() var val float64 for _, v := range cpus { - val = v + val = float64(v) break } self.Data["AVRG"] = append(self.Data["AVRG"], val) @@ -118,20 +118,20 @@ func (self *CpuWidget) update() { if self.ShowPerCpuLoad { go func() { - cpus := make(map[string]float64) + cpus := make(map[string]int) devices.UpdateCPU(cpus, self.updateInterval, true) self.Lock() defer self.Unlock() self.updateLock.Lock() defer self.updateLock.Unlock() for key, percent := range cpus { - self.Data[key] = append(self.Data[key], percent) - self.Labels[key] = fmt.Sprintf("%3.0f%%", percent) + self.Data[key] = append(self.Data[key], float64(percent)) + self.Labels[key] = fmt.Sprintf("%d%%", percent) if self.metric != nil { if self.metric[key] == nil { log.Printf("no metrics for %s", key) } else { - self.metric[key].Set(percent) + self.metric[key].Set(float64(percent)) } } } diff --git a/widgets/mem.go b/widgets/mem.go index f0494cf..b80b68c 100644 --- a/widgets/mem.go +++ b/widgets/mem.go @@ -2,6 +2,7 @@ package widgets import ( "fmt" + "log" "time" "github.com/prometheus/client_golang/prometheus" @@ -27,7 +28,8 @@ func NewMemWidget(updateInterval time.Duration, horizontalScale int) *MemWidget mems := make(map[string]devices.MemoryInfo) devices.UpdateMem(mems) for name, mem := range mems { - self.Data[name] = []float64{mem.UsedPercent} + log.Printf("setting %s to %v", name, mem) + self.Data[name] = []float64{0} self.renderMemInfo(name, mem) } @@ -36,6 +38,7 @@ func NewMemWidget(updateInterval time.Duration, horizontalScale int) *MemWidget self.Lock() devices.UpdateMem(mems) for label, mi := range mems { + log.Printf(" updating %s to %v", label, mi) self.renderMemInfo(label, mi) if self.metrics != nil && self.metrics[label] != nil { self.metrics[label].Set(mi.UsedPercent) -- cgit v1.2.3