diff options
-rw-r--r-- | CHANGELOG.md | 4 | ||||
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | cmd/gotop/main.go | 4 | ||||
-rw-r--r-- | layout/layout.go | 5 | ||||
-rw-r--r-- | layouts/kitchensink | 5 | ||||
-rw-r--r-- | termui/gauge.go | 22 | ||||
-rw-r--r-- | widgets/batterygauge.go | 77 |
7 files changed, 116 insertions, 3 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 065589e..9b15345 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,9 +15,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [3.4.x] - -- Adds metrics. If run with the `--export :2112` flag (`:2112` is a port), +- Added: metrics. If run with the `--export :2112` flag (`:2112` is a port), metrics are exposed as Prometheus metrics on that port and can be HTTP GET-ted. +- Added: a battery gauge as a `power` widget; battery as a bar rather than + a histogram. ## [3.3.1] - 2020-02-18 @@ -94,7 +94,7 @@ and these are separated by spaces. 1. Each line is a row 2. Empty lines are skipped 3. Spaces are compressed (so you can do limited visual formatting) -4. Legal widget names are: cpu, disk, mem, temp, batt, net, procs +4. Legal widget names are: cpu, disk, mem, temp, batt, net, procs, power 5. Widget names are not case sensitive 4. The simplest row is a single widget, by name, e.g. ``` diff --git a/cmd/gotop/main.go b/cmd/gotop/main.go index 1d1f4df..a85f147 100644 --- a/cmd/gotop/main.go +++ b/cmd/gotop/main.go @@ -27,7 +27,7 @@ import ( const ( appName = "gotop" - version = "3.3.1" + version = "3.4.0" graphHorizontalScaleDelta = 3 defaultUI = "cpu\ndisk/1 2:mem/2\ntemp\nnet procs" @@ -43,6 +43,7 @@ var ( stderrLogger = log.New(os.Stderr, "", 0) ) +// TODO: Add tab completion for Linux https://gist.github.com/icholy/5314423 func parseArgs(conf *gotop.Config) error { usage := ` Usage: gotop [options] @@ -346,6 +347,7 @@ func makeConfig() gotop.Config { return conf } +// TODO: mpd visualizer widget func main() { // Set up default config conf := makeConfig() diff --git a/layout/layout.go b/layout/layout.go index 3fc3bb5..359b47e 100644 --- a/layout/layout.go +++ b/layout/layout.go @@ -59,6 +59,7 @@ func Layout(wl layout, c gotop.Config) (*MyGrid, error) { // rows as the largest row span object in the row, and produce an uber-row // containing all that stuff. It returns a slice without the consumed elements. func processRow(c gotop.Config, numRows int, rowDefs [][]widgetRule) (ui.GridItem, [][]widgetRule) { + // FIXME: 3\:A 2\:B\nC should stop consuming rows when all columns are full // Recursive function #3. See the comment in deepFindProc. if len(rowDefs) < 1 { return ui.GridItem{}, [][]widgetRule{} @@ -190,6 +191,10 @@ func makeWidget(c gotop.Config, widRule widgetRule) interface{} { i++ } w = b + case "power": + b := widgets.NewBatteryGauge() + b.BarColor = ui.Color(c.Colorscheme.ProcCursor) + w = b default: log.Printf("Invalid widget name %s. Must be one of %v", widRule.Widget, widgetNames) return ui.NewBlock() diff --git a/layouts/kitchensink b/layouts/kitchensink new file mode 100644 index 0000000..762ff91 --- /dev/null +++ b/layouts/kitchensink @@ -0,0 +1,5 @@ +cpu/2 mem/1 +3:temp/1 2:disk/2 + power + power +net procs diff --git a/termui/gauge.go b/termui/gauge.go new file mode 100644 index 0000000..db9a9c0 --- /dev/null +++ b/termui/gauge.go @@ -0,0 +1,22 @@ +package termui + +import ( + . "github.com/gizak/termui/v3" + gizak "github.com/gizak/termui/v3/widgets" +) + +// LineGraph implements a line graph of data points. +type Gauge struct { + *gizak.Gauge +} + +func NewGauge() *Gauge { + return &Gauge{ + Gauge: gizak.NewGauge(), + } +} + +func (self *Gauge) Draw(buf *Buffer) { + self.Gauge.Draw(buf) + self.Gauge.SetRect(self.Min.X, self.Min.Y, self.Inner.Dx(), self.Inner.Dy()) +} diff --git a/widgets/batterygauge.go b/widgets/batterygauge.go new file mode 100644 index 0000000..04b1434 --- /dev/null +++ b/widgets/batterygauge.go @@ -0,0 +1,77 @@ +package widgets + +import ( + "fmt" + "log" + //"math" + //"strconv" + "time" + + "github.com/distatus/battery" + "github.com/prometheus/client_golang/prometheus" + + . "github.com/xxxserxxx/gotop/termui" +) + +type BatteryGauge struct { + *Gauge + metric prometheus.Gauge +} + +func NewBatteryGauge() *BatteryGauge { + self := &BatteryGauge{Gauge: NewGauge()} + self.Title = " Power Level " + + self.update() + + go func() { + for range time.NewTicker(time.Second).C { + self.Lock() + self.update() + self.Unlock() + } + }() + + return self +} + +func (b *BatteryGauge) EnableMetric() { + bats, err := battery.GetAll() + if err != nil { + log.Printf("error setting up metrics: %v", err) + return + } + mx := 0.0 + cu := 0.0 + for _, bat := range bats { + mx += bat.Full + cu += bat.Current + gauge := prometheus.NewGauge(prometheus.GaugeOpts{ + Namespace: "gotop", + Subsystem: "battery", + Name: "total", + }) + gauge.Set(cu / mx) + b.metric = gauge + prometheus.MustRegister(gauge) + } +} + +func (self *BatteryGauge) update() { + bats, err := battery.GetAll() + if err != nil { + log.Printf("error setting up metrics: %v", err) + return + } + mx := 0.0 + cu := 0.0 + for _, bat := range bats { + mx += bat.Full + cu += bat.Current + } + self.Percent = int((cu / mx) * 100.0) + self.Label = fmt.Sprintf("%d%%", self.Percent) + if self.metric != nil { + self.metric.Set(cu / mx) + } +} |