summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSean E. Russell <ser@ser1.net>2020-04-16 13:28:18 -0500
committerSean E. Russell <ser@ser1.net>2020-04-16 13:28:18 -0500
commit9e1b63be3250661124babf270f8a13326ef0d2f0 (patch)
treef2ae4b5cf45e5797e005ada72d1087f3c50dc4ee
parentd22c36e7195b80c199c25a7a0ed2525555e1de00 (diff)
Closes #46, option to display network traffic as mbps. This can be set on the command line with --mbps, or toggled while running with `b`
-rw-r--r--CHANGELOG.md13
-rw-r--r--README.md17
-rw-r--r--cmd/gotop/main.go18
-rw-r--r--config.go3
-rw-r--r--layout/layout.go40
-rw-r--r--layout/parser.go108
-rw-r--r--layouts/many_columns_test41
-rw-r--r--widgets/batterygauge.go1
-rw-r--r--widgets/help.go3
-rw-r--r--widgets/net.go31
10 files changed, 173 insertions, 102 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d854f55..ba003ac 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -18,9 +18,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Adds support for system-wide configurations. This improves support for package maintainers.
-- Help function to print key bindings
-- Help prints locations of config files (color schemes & layouts)
-- Help prints location of logs
+- Help function to print key bindings.
+- Help prints locations of config files (color schemes & layouts).
+- Help prints location of logs.
+- CLI option to scale out (#84).
+- Ability to report network traffic rates as mbps (#46).
### Changed
@@ -31,6 +33,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- configdir, logdir, and logfile options in the config file are no longer used. gotop looks for a configuration file, layouts, and colorschemes in the following order: command-line; `pwd`; user-home, and finally a system-wide path. The paths depend on the OS and whether XDG is in use.
+### Fixed
+
+- Help & statusbar don't obey theme (#47).
+- Fix help text layout.
+
## [3.5.1] - 2020-04-09
This is a bug fix release.
diff --git a/README.md b/README.md
index 31e31ea..5b3ce0f 100644
--- a/README.md
+++ b/README.md
@@ -120,6 +120,7 @@ Move `gotop` to somewhere in your `$PATH`.
- `h`: scale in
- `l`: scale out
- `?`: toggles keybind help menu
+- `b`: toggles display of network traffic in mbps or TX (or RX) per second
### Mouse
@@ -207,21 +208,7 @@ build massive edifices, you're in for disappointment.
### CLI Options
-`-c`, `--color=NAME` Set a colorscheme.
-`-m`, `--minimal` Only show CPU, Mem and Process widgets. (DEPRECATED, use `-l minimal`)
-`-r`, `--rate=RATE` Number of times per second to update CPU and Mem widgets [default: 1].
-`-V`, `--version` Print version and exit.
-`-p`, `--percpu` Show each CPU in the CPU widget.
-`-a`, `--averagecpu` Show average CPU in the CPU widget.
-`-f`, `--fahrenheit` Show temperatures in fahrenheit.
-`-s`, `--statusbar` Show a statusbar with the time.
-`-b`, `--battery` Show battery level widget (`minimal` turns off). (DEPRECATED, use `-l battery`)
-`-i`, `--interface=NAME` Select network interface [default: all].
-`-l`, `--layout=NAME` Choose a layout. gotop searches for a file by NAME in \$XDG_CONFIG_HOME/gotop, then relative to the current path. "-" reads a layout from stdin, allowing for simple, one-off layouts such as `echo net | gotop -l -`
-
-Several interfaces can be defined using comma separated values.
-
-Interfaces can also be ignored using `!`
+Run `gotop -h` to see the list of all command line options.
## More screen shots
diff --git a/cmd/gotop/main.go b/cmd/gotop/main.go
index 5dbcd3e..5728128 100644
--- a/cmd/gotop/main.go
+++ b/cmd/gotop/main.go
@@ -74,12 +74,13 @@ 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]. Several interfaces can be defined using comma separated values. Interfaces can also be ignored using !
+ -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.
- --test Runs tests and exits with success/failure code
- --print-paths List out the paths that gotop will look for gotop.conf, layouts, color schemes, and extensions
- --print-keys Show the keyboard bindings
+ -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.
+ --mbps Net widget shows mb(its)ps for RX/TX instead of scaled bytes per second.
+ --test Runs tests and exits with success/failure code.
+ --print-paths List out the paths that gotop will look for gotop.conf, layouts, color schemes, and extensions.
+ --print-keys Show the keyboard bindings.
Built-in layouts:
default
@@ -184,6 +185,9 @@ Log files are stored in %s
}
conf.GraphHorizontalScale = scl
}
+ if args["--mbps"].(bool) {
+ conf.Mbps = true
+ }
if args["--print-paths"].(bool) {
paths := make([]string, 0)
for _, d := range conf.ConfigDir.QueryFolders(configdir.All) {
@@ -308,6 +312,10 @@ func eventLoop(c gotop.Config, grid *layout.MyGrid) {
ui.Render(item)
}
}
+ case "b":
+ if grid.Net != nil {
+ grid.Net.Mbps = !grid.Net.Mbps
+ }
case "<Resize>":
ui.Render(grid)
if statusbar {
diff --git a/config.go b/config.go
index 41b5278..3d1ae38 100644
--- a/config.go
+++ b/config.go
@@ -33,6 +33,7 @@ type Config struct {
MaxLogSize int64
ExportPort string
Extensions []string
+ Mbps bool
Test bool
}
@@ -131,6 +132,8 @@ func (conf *Config) Load() error {
conf.ExportPort = kv[1]
case "extensions":
conf.Extensions = strings.Split(kv[1], ",")
+ case "mbps":
+ conf.Mbps = true
}
}
diff --git a/layout/layout.go b/layout/layout.go
index 5cd8f24..9fc4452 100644
--- a/layout/layout.go
+++ b/layout/layout.go
@@ -25,6 +25,7 @@ type MyGrid struct {
*ui.Grid
Lines []widgets.Scalable
Proc *widgets.ProcWidget
+ Net *widgets.NetWidget
}
var widgetNames []string = []string{"cpu", "disk", "mem", "temp", "net", "procs", "batt"}
@@ -48,10 +49,25 @@ func Layout(wl layout, c gotop.Config) (*MyGrid, error) {
rh := float64(heights[i]) / float64(maxHeight)
rgs = append(rgs, ui.NewRow(rh, ur...))
}
- grid := &MyGrid{ui.NewGrid(), nil, nil}
+ grid := &MyGrid{ui.NewGrid(), nil, nil, nil}
grid.Set(rgs...)
grid.Lines = deepFindScalable(rgs)
- grid.Proc = deepFindProc(uiRows)
+ res := deepFindWidget(uiRows, func(gs interface{}) interface{} {
+ p, ok := gs.(*widgets.ProcWidget)
+ if ok {
+ return p
+ }
+ return nil
+ })
+ grid.Proc, _ = res.(*widgets.ProcWidget)
+ res = deepFindWidget(uiRows, func(gs interface{}) interface{} {
+ p, ok := gs.(*widgets.NetWidget)
+ if ok {
+ return p
+ }
+ return nil
+ })
+ grid.Net, _ = res.(*widgets.NetWidget)
return grid, nil
}
@@ -189,6 +205,7 @@ func makeWidget(c gotop.Config, widRule widgetRule) interface{} {
n.Lines[0].TitleColor = ui.Color(c.Colorscheme.BorderLabel)
n.Lines[1].LineColor = ui.Color(c.Colorscheme.Sparkline)
n.Lines[1].TitleColor = ui.Color(c.Colorscheme.BorderLabel)
+ n.Mbps = c.Mbps
w = n
case "procs":
p := widgets.NewProcWidget()
@@ -267,20 +284,19 @@ func countMaxHeight(rs [][]widgetRule) int {
return ttl
}
-// deepFindProc looks in the UI widget tree for the ProcWidget,
-// and returns it if found or nil if not.
-func deepFindProc(gs interface{}) *widgets.ProcWidget {
+// deepFindWidget looks in the UI widget tree for a widget, and returns it if found or nil if not.
+func deepFindWidget(gs interface{}, test func(v interface{}) interface{}) interface{} {
// Recursive function #1. Recursion is OK here because the number
// of UI elements, even in a very complex UI, is going to be
// relatively small.
t, ok := gs.(ui.GridItem)
if ok {
- return deepFindProc(t.Entry)
+ return deepFindWidget(t.Entry, test)
}
es, ok := gs.([]ui.GridItem)
if ok {
for _, g := range es {
- v := deepFindProc(g)
+ v := deepFindWidget(g, test)
if v != nil {
return v
}
@@ -289,7 +305,7 @@ func deepFindProc(gs interface{}) *widgets.ProcWidget {
fs, ok := gs.([]interface{})
if ok {
for _, g := range fs {
- v := deepFindProc(g)
+ v := deepFindWidget(g, test)
if v != nil {
return v
}
@@ -298,17 +314,13 @@ func deepFindProc(gs interface{}) *widgets.ProcWidget {
fs2, ok := gs.([][]interface{})
if ok {
for _, g := range fs2 {
- v := deepFindProc(g)
+ v := deepFindWidget(g, test)
if v != nil {
return v
}
}
}
- p, ok := gs.(*widgets.ProcWidget)
- if ok {
- return p
- }
- return nil
+ return test(gs)
}
// deepFindScalable looks in the UI widget tree for Scalable widgets,
diff --git a/layout/parser.go b/layout/parser.go
index 024fabb..f35171e 100644
--- a/layout/parser.go
+++ b/layout/parser.go
@@ -8,64 +8,68 @@ import (
"strings"
)
-// The syntax for the layout specification is:
-// ```
-// (rowspan:)?widget(/weight)?
-// ```
-// 1. Each line is a row
-// 2. Empty lines are skipped
-// 3. Spaces are compressed
-// 4. Legal widget names are: cpu, disk, mem, temp, batt, net, procs
-// 5. Names are not case sensitive
-// 4. The simplest row is a single widget, by name, e.g.
-// ```
-// cpu
-// ```
-// 5. Widgets with no weights have a weight of 1.
-// 6. If multiple widgets are put on a row with no weights, they will all have
-// the same width.
-// 7. Weights are integers
-// 8. A widget will have a width proportional to its weight divided by the
-// total weight count of the row. E.g.,
-// ```
-// cpu net
-// disk/2 mem/4
-// ```
-// The first row will have two widgets: the CPU and network widgets; each
-// will be 50% of the total width wide. The second row will have two
-// widgets: disk and memory; the first will be 2/6 ~= 33% wide, and the
-// second will be 5/7 ~= 67% wide (or, memory will be twice as wide as disk).
-// 9. If prefixed by a number and colon, the widget will span that number of
-// rows downward. E.g.
-// ```
-// 2:cpu
-// mem
-// ```
-// The CPU widget will be twice as high as the memory widget. Similarly,
-// ```
-// mem 2:cpu
-// net
-// ```
-// memory and network will be in the same row as CPU, one over the other,
-// and each half as high as CPU.
-// 10. Negative, 0, or non-integer weights will be recorded as "1". Same for row spans.
-// 11. Unrecognized widgets will cause the application to abort.
-// 12. In rows with multi-row spanning widgets **and** weights, weights in
-// lower rows are ignored. Put the weight on the widgets in that row, not
-// in later (spanned) rows.
-// 13. Widgets are filled in top down, left-to-right order.
-// 14. The larges row span in a row defines the top-level row span; all smaller
-// row spans constitude sub-rows in the row. For example, `cpu mem/3 net/5`
-// means that net/5 will be 5 rows tall overall, and mem will compose 3 of
-// them. If following rows do not have enough widgets to fill the gaps,
-// spacers will be used.
+/**********************************************************************************
+The syntax for the layout specification is:
+```
+(rowspan:)?widget(/weight)?
+```
+1. Each line is a row
+2. Empty lines are skipped
+3. Spaces are compressed
+4. Legal widget names are: cpu, disk, mem, temp, batt, net, procs
+5. Names are not case sensitive
+4. The simplest row is a single widget, by name, e.g.
+ ```
+ cpu
+ ```
+5. Widgets with no weights have a weight of 1.
+6. If multiple widgets are put on a row with no weights, they will all have
+ the same width.
+7. Weights are integers
+8. A widget will have a width proportional to its weight divided by the
+ total weight count of the row. E.g.,
+ ```
+ cpu net
+ disk/2 mem/4
+ ```
+ The first row will have two widgets: the CPU and network widgets; each
+ will be 50% of the total width wide. The second row will have two
+ widgets: disk and memory; the first will be 2/6 ~= 33% wide, and the
+ second will be 5/7 ~= 67% wide (or, memory will be twice as wide as disk).
+9. If prefixed by a number and colon, the widget will span that number of
+ rows downward. E.g.
+ ```
+ 2:cpu
+ mem
+ ```
+ The CPU widget will be twice as high as the memory widget. Similarly,
+ ```
+ mem 2:cpu
+ net
+ ```
+ memory and network will be in the same row as CPU, one over the other,
+ and each half as high as CPU.
+10. Negative, 0, or non-integer weights will be recorded as "1". Same for row spans.
+11. Unrecognized widgets will cause the application to abort.
+12. In rows with multi-row spanning widgets **and** weights, weights in
+ lower rows are ignored. Put the weight on the widgets in that row, not
+ in later (spanned) rows.
+13. Widgets are filled in top down, left-to-right order.
+14. The larges row span in a row defines the top-level row span; all smaller
+ row spans constitude sub-rows in the row. For example, `cpu mem/3 net/5`
+ means that net/5 will be 5 rows tall overall, and mem will compose 3 of
+ them. If following rows do not have enough widgets to fill the gaps,
+ spacers will be used.
+15. Lines beginning with "#" will be ignored. It must be the first character of
+ the line.
+**********************************************************************************/
func ParseLayout(i io.Reader) layout {
r := bufio.NewScanner(i)
rv := layout{Rows: make([][]widgetRule, 0)}
var lineNo int
for r.Scan() {
l := strings.TrimSpace(r.Text())
- if l == "" {
+ if l == "" || l[0] == '#' {
continue
}
row := make([]widgetRule, 0)
diff --git a/layouts/many_columns_test b/layouts/many_columns_test
index f2d57e3..7525713 100644
--- a/layouts/many_columns_test
+++ b/layouts/many_columns_test
@@ -1,4 +1,39 @@
-cpu/2 mem/1 6:procs/2
+# This should look like:
+#
+# + + + + + +
+# +-------------------+---------+-------------------+ +
+# | CPU | MEM | PROCS |
+# +---------+---------+---------+ | +
+# | TEMPS | DISK | |
+# | | | | +
+# | | | |
+# | +-------------------+ | +
+# | | POWER | |
+# +---------+-------------------+ | +
+# | NET | |
+# +-----------------------------+-------------------+ +
+#
+
+# Not all of the weights are necessary (e.g., power, net) nor
+# the spacing, but it makes the layout easier to visualize.
+
+cpu/2 mem/1 5:procs/2
3:temp/1 2:disk/2
-power
-net procs
+ power/2
+net/3
+
+# + + + + + +
+# +===============================+=====================+
+# ⋮+-------------------+---------+⋮+-------------------+⋮+
+# ⋮| CPU | MEM |⋮| PROCS |⋮
+# ⋮+---------+---------+---------+⋮| |⋮+
+# ⋮| TEMPS | DISK |⋮| |⋮
+# ⋮| | |⋮| |⋮+
+# ⋮| | |⋮| |⋮
+# ⋮| +-------------------+⋮| |⋮+
+# ⋮| | POWER |⋮| |⋮
+# ⋮+---------+-------------------+⋮| |⋮+
+# ⋮| NET |⋮| |⋮
+# ⋮+-----------------------------+⋮+-------------------+⋮+
+# +===============================+=====================+
+#
diff --git a/widgets/batterygauge.go b/widgets/batterygauge.go
index d447713..534c1cf 100644
--- a/widgets/batterygauge.go
+++ b/widgets/batterygauge.go
@@ -12,7 +12,6 @@ import (
. "github.com/xxxserxxx/gotop/v3/termui"
)
-// FIXME 3.5.1 is 0% always
type BatteryGauge struct {
*Gauge
metric prometheus.Gauge
diff --git a/widgets/help.go b/widgets/help.go
index 8aab35d..012ca9d 100644
--- a/widgets/help.go
+++ b/widgets/help.go
@@ -40,6 +40,9 @@ Process filtering:
CPU and Mem graph scaling:
- h: scale in
- l: scale out
+
+Network:
+ - b: toggle between mbps and scaled bytes per second
`
type HelpMenu struct {
diff --git a/widgets/net.go b/widgets/net.go
index 3f03936..249d0c2 100644
--- a/widgets/net.go
+++ b/widgets/net.go
@@ -28,6 +28,7 @@ type NetWidget struct {
NetInterface []string
sentMetric prometheus.Counter
recvMetric prometheus.Counter
+ Mbps bool
}
// TODO: state:merge #169 % option for network use (jrswab/networkPercentage)
@@ -144,19 +145,31 @@ func (self *NetWidget) update() {
self.totalBytesRecv = totalBytesRecv
self.totalBytesSent = totalBytesSent
+ rx, tx := "RX/s", "TX/s"
+ if self.Mbps {
+ rx, tx = "mbps", "mbps"
+ }
+ format := " %s: %9.1f %2s/s"
+
+ var total, recent uint64
+ var label, unitRecent, rate string
+ var recentConverted float64
// render widget titles
for i := 0; i < 2; i++ {
- total, label, recent := func() (uint64, string, uint64) {
- if i == 0 {
- return totalBytesRecv, "RX", recentBytesRecv
- }
- return totalBytesSent, "TX", recentBytesSent
- }()
+ if i == 0 {
+ total, label, rate, recent = totalBytesRecv, "RX", rx, recentBytesRecv
+ } else {
+ total, label, rate, recent = totalBytesSent, "TX", tx, recentBytesSent
+ }
- recentConverted, unitRecent := utils.ConvertBytes(uint64(recent))
- totalConverted, unitTotal := utils.ConvertBytes(uint64(total))
+ totalConverted, unitTotal := utils.ConvertBytes(total)
+ if self.Mbps {
+ recentConverted, unitRecent, format = float64(recent)*0.000008, "", " %s: %11.3f %2s"
+ } else {
+ recentConverted, unitRecent = utils.ConvertBytes(recent)
+ }
self.Lines[i].Title1 = fmt.Sprintf(" Total %s: %5.1f %s", label, totalConverted, unitTotal)
- self.Lines[i].Title2 = fmt.Sprintf(" %s/s: %9.1f %2s/s", label, recentConverted, unitRecent)
+ self.Lines[i].Title2 = fmt.Sprintf(format, rate, recentConverted, unitRecent)
}
}