Fixes #92, configurable temps; help text & docs clean-up; versions are now built into binaries at compile time; clean up old extensions params; adds --list command; adds --write-config command; fixes bug in colorscheme loading; fixes bug in Colorschemes -- all had empty Name attrs; adds ability to list devices.
This commit is contained in:
parent
3fcab5a420
commit
5ada5315d9
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
|
@ -29,5 +29,3 @@ jobs:
|
||||||
repository: xxxserxxx/gotop-linux
|
repository: xxxserxxx/gotop-linux
|
||||||
event-type: my-release
|
event-type: my-release
|
||||||
client-payload: '{"tag": "${{ steps.tag_name.outputs.tag }}"}'
|
client-payload: '{"tag": "${{ steps.tag_name.outputs.tag }}"}'
|
||||||
|
|
||||||
# TODO: Build the plugins too
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
- Ignore lines matching `/^#.*/` in layout files.
|
- Ignore lines matching `/^#.*/` in layout files.
|
||||||
- Instructions for Gentoo (thanks @tormath1!)
|
- Instructions for Gentoo (thanks @tormath1!)
|
||||||
- Graph labels that don't fit (vertically) in the window are now drawn in additional columns (#40)
|
- Graph labels that don't fit (vertically) in the window are now drawn in additional columns (#40)
|
||||||
|
- Adds ability to filter reported temperatures (#92)
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
@ -44,6 +45,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
- Memory line colors were inconsistently assigned (#91)
|
- Memory line colors were inconsistently assigned (#91)
|
||||||
- The disk code was truncating values instead of rounding (#90)
|
- The disk code was truncating values instead of rounding (#90)
|
||||||
- Temperatures on Darwin were all over the place, and wrong (#48)
|
- Temperatures on Darwin were all over the place, and wrong (#48)
|
||||||
|
- Config file loading from `~/.config/gotop` wasn't working
|
||||||
|
|
||||||
## [3.5.1] - 2020-04-09
|
## [3.5.1] - 2020-04-09
|
||||||
|
|
||||||
|
|
61
README.md
61
README.md
|
@ -127,12 +127,30 @@ Move `gotop` to somewhere in your `$PATH`.
|
||||||
- click to select process
|
- click to select process
|
||||||
- mouse wheel to scroll through processes
|
- mouse wheel to scroll through processes
|
||||||
|
|
||||||
|
### Config file
|
||||||
|
|
||||||
|
Most command-line settings can be persisted into a configuration file. The config file is named `gotop.conf` and can be located in several places. The first place gotop will look is in the current directory; after this, the locations depend on the OS and distribution. On Linux using XDG, for instance, the home location of `~/.config/gotop/gotop.conf` is the second location. The last location is a system-wide global location, such as `/etc/gotop/gotop.conf`. The `-h` help command will print out all of the locations, in order. Command-line options override values in any config files, and only the first config file found is loaded.
|
||||||
|
|
||||||
|
A configuration file can be created using the `--write-config` command-line argument. This will try to place the config file in the home config directory (the second location), but if it's unable to do so it'll write a file to the current directory.
|
||||||
|
|
||||||
|
Config file changes can be made by combining command-line arguments with `--write-config`. For example, to persist the `solarized` theme, call:
|
||||||
|
|
||||||
|
```
|
||||||
|
gotop -c solarized --write-config
|
||||||
|
```
|
||||||
|
|
||||||
### Colorschemes
|
### Colorschemes
|
||||||
|
|
||||||
gotop ships with a few colorschemes which can be set with the `-c` flag followed by the name of one. You can find all the colorschemes in the [colorschemes folder](./colorschemes).
|
gotop ships with a few colorschemes which can be set with the `-c` flag followed by the name of one. You can find all the colorschemes in the [colorschemes folder](./colorschemes).
|
||||||
|
|
||||||
To make a custom colorscheme, check out the [template](./colorschemes/template.go) for instructions and then use [default.json](./colorschemes/default.json) as a starter. Then put the file at `~/.config/gotop/<name>.json` and load it with `gotop -c <name>`. Colorschemes PR's are welcome!
|
To make a custom colorscheme, check out the [template](./colorschemes/template.go) for instructions and then use [default.json](./colorschemes/default.json) as a starter. Then put the file at `~/.config/gotop/<name>.json` and load it with `gotop -c <name>`. Colorschemes PR's are welcome!
|
||||||
|
|
||||||
|
To list all built-in color schemes, call:
|
||||||
|
|
||||||
|
```
|
||||||
|
gotop --list colorschemes
|
||||||
|
```
|
||||||
|
|
||||||
### Layouts
|
### Layouts
|
||||||
|
|
||||||
gotop can parse and render layouts from a specification file. The format is
|
gotop can parse and render layouts from a specification file. The format is
|
||||||
|
@ -206,6 +224,49 @@ and these are separated by spaces.
|
||||||
Yes, you're clever enough to break the layout algorithm, but if you try to
|
Yes, you're clever enough to break the layout algorithm, but if you try to
|
||||||
build massive edifices, you're in for disappointment.
|
build massive edifices, you're in for disappointment.
|
||||||
|
|
||||||
|
To list all built-in color schemes, call:
|
||||||
|
|
||||||
|
```
|
||||||
|
gotop --list layouts
|
||||||
|
```
|
||||||
|
|
||||||
|
### Device filtering
|
||||||
|
|
||||||
|
Some devices have quite a number of data points; on OSX, for instance, there are dozens of temperature readings. These can be filtered through a configuration file. There is no command-line argument for this filter.
|
||||||
|
|
||||||
|
The list will grow, but for now the only device that supports filtering is the temperature widget. The configuration entry is called `temperature`, and it contains an exact-match list of comma-separated values with no spaces. To see the list of valid values, run gotop with the `--list devices` command. Gotop will print out the type of device and the legal values. For example, on Linux:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ gotop --list devices
|
||||||
|
Temperatures:
|
||||||
|
acpitz
|
||||||
|
nvme_composite
|
||||||
|
nvme_sensor1
|
||||||
|
nvme_sensor2
|
||||||
|
pch_cannonlake
|
||||||
|
coretemp_packageid0
|
||||||
|
coretemp_core0
|
||||||
|
coretemp_core1
|
||||||
|
coretemp_core2
|
||||||
|
coretemp_core3
|
||||||
|
ath10k_hwmon
|
||||||
|
```
|
||||||
|
You might then add the following line to the config file. First, find where gotop looks for config files:
|
||||||
|
```
|
||||||
|
$ gotop -h | tail -n 6
|
||||||
|
Colorschemes & layouts that are not built-in are searched for (in order) in:
|
||||||
|
/home/USER/workspace/gotop.d/gotop, /home/USER/.config/gotop, /etc/xdg/gotop
|
||||||
|
The first path in this list is always the cwd. The config file
|
||||||
|
'gotop.config' can also reside in one of these directories.
|
||||||
|
|
||||||
|
Log files are stored in /home/ser/.cache/gotop/errors.log
|
||||||
|
```
|
||||||
|
So you might use `/home/YOU/.config/gotop.conf`, and add (or modify) this line:
|
||||||
|
```
|
||||||
|
temperatures=acpitz,coretemp_core0,ath10k_hwmon
|
||||||
|
```
|
||||||
|
This will cause the temp widget to show only four of the eleven temps.
|
||||||
|
|
||||||
### CLI Options
|
### CLI Options
|
||||||
|
|
||||||
Run `gotop -h` to see the list of all command line options.
|
Run `gotop -h` to see the list of all command line options.
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
@ -20,6 +21,7 @@ import (
|
||||||
|
|
||||||
"github.com/xxxserxxx/gotop/v3"
|
"github.com/xxxserxxx/gotop/v3"
|
||||||
"github.com/xxxserxxx/gotop/v3/colorschemes"
|
"github.com/xxxserxxx/gotop/v3/colorschemes"
|
||||||
|
"github.com/xxxserxxx/gotop/v3/devices"
|
||||||
"github.com/xxxserxxx/gotop/v3/layout"
|
"github.com/xxxserxxx/gotop/v3/layout"
|
||||||
"github.com/xxxserxxx/gotop/v3/logging"
|
"github.com/xxxserxxx/gotop/v3/logging"
|
||||||
w "github.com/xxxserxxx/gotop/v3/widgets"
|
w "github.com/xxxserxxx/gotop/v3/widgets"
|
||||||
|
@ -37,8 +39,8 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// TODO: Set this at compile time; having to check this in sucks.
|
Version = "0.0.0"
|
||||||
Version = "3.6.dev"
|
BuildDate = "Hadean"
|
||||||
conf gotop.Config
|
conf gotop.Config
|
||||||
help *w.HelpMenu
|
help *w.HelpMenu
|
||||||
bar *w.StatusBar
|
bar *w.StatusBar
|
||||||
|
@ -48,17 +50,14 @@ var (
|
||||||
|
|
||||||
// TODO: Add tab completion for Linux https://gist.github.com/icholy/5314423
|
// TODO: Add tab completion for Linux https://gist.github.com/icholy/5314423
|
||||||
// TODO: state:merge #135 linux console font (cmatsuoka/console-font)
|
// TODO: state:merge #135 linux console font (cmatsuoka/console-font)
|
||||||
// TODO: state:deferred 157 FreeBSD fixes & Nvidia GPU support (kraust/master). Significant CPU use impact for NVidia changes.
|
|
||||||
// TODO: Virtual devices from Prometeus metrics @feature
|
|
||||||
// TODO: Abstract out the UI toolkit. mum4k/termdash, VladimirMarkelov/clui, gcla/gowid, rivo/tview, marcusolsson/tui-go might work better for some OS/Archs. Performance/memory use comparison would be interesting.
|
// TODO: Abstract out the UI toolkit. mum4k/termdash, VladimirMarkelov/clui, gcla/gowid, rivo/tview, marcusolsson/tui-go might work better for some OS/Archs. Performance/memory use comparison would be interesting.
|
||||||
// TODO: Add fans
|
|
||||||
func parseArgs(conf *gotop.Config) error {
|
func parseArgs(conf *gotop.Config) error {
|
||||||
cds := conf.ConfigDir.QueryFolders(configdir.All)
|
cds := conf.ConfigDir.QueryFolders(configdir.All)
|
||||||
cpaths := make([]string, len(cds))
|
cpaths := make([]string, len(cds))
|
||||||
for i, p := range cds {
|
for i, p := range cds {
|
||||||
cpaths[i] = p.Path
|
cpaths[i] = p.Path
|
||||||
}
|
}
|
||||||
usage := fmt.Sprintf(`
|
usage := fmt.Sprintln(`
|
||||||
Usage: gotop [options]
|
Usage: gotop [options]
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
|
@ -77,40 +76,15 @@ Options:
|
||||||
-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.
|
-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, --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.
|
|
||||||
--mbps Net widget shows mb(its)ps for RX/TX instead of scaled bytes per second.
|
--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.
|
--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.
|
--list <devices|layouts|colorschemes|paths|keys>
|
||||||
--print-keys Show the keyboard bindings.
|
devices: Prints out device names for widgets supporting filters.
|
||||||
|
layouts: Lists build-in layouts
|
||||||
Built-in layouts:
|
colorschemes: Lists built-in colorschemes
|
||||||
default
|
paths: List out the paths that gotop will look for gotop.conf, layouts, and color schemes.
|
||||||
minimal
|
keys: Show the keyboard bindings.
|
||||||
battery
|
--write-config Write out a sample config file, either to the home config location, or current directory. Command-line arguments specificed at the same time will overwrite values in the config file.`)
|
||||||
kitchensink
|
|
||||||
|
|
||||||
Colorschemes:
|
|
||||||
default
|
|
||||||
default-dark (for white background)
|
|
||||||
solarized
|
|
||||||
solarized16-dark
|
|
||||||
solarized16-light
|
|
||||||
monokai
|
|
||||||
vice
|
|
||||||
|
|
||||||
Colorschemes and layouts that are not built-in are searched for (in order) in:
|
|
||||||
%s
|
|
||||||
The first path in this list is always the cwd.
|
|
||||||
|
|
||||||
Log files are stored in %s
|
|
||||||
|
|
||||||
`, strings.Join(cpaths, ", "), filepath.Join(conf.ConfigDir.QueryCacheFolder().Path, logging.LOGFILE))
|
|
||||||
|
|
||||||
var err error
|
|
||||||
conf.Colorscheme, err = colorschemes.FromName(conf.ConfigDir, "default")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
args, err := docopt.ParseArgs(usage, os.Args[1:], Version)
|
args, err := docopt.ParseArgs(usage, os.Args[1:], Version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -127,6 +101,7 @@ Log files are stored in %s
|
||||||
}
|
}
|
||||||
conf.Colorscheme = cs
|
conf.Colorscheme = cs
|
||||||
}
|
}
|
||||||
|
|
||||||
if args["--averagecpu"].(bool) {
|
if args["--averagecpu"].(bool) {
|
||||||
conf.AverageLoad, _ = args["--averagecpu"].(bool)
|
conf.AverageLoad, _ = args["--averagecpu"].(bool)
|
||||||
}
|
}
|
||||||
|
@ -166,10 +141,6 @@ Log files are stored in %s
|
||||||
if val, _ := args["--interface"]; val != nil {
|
if val, _ := args["--interface"]; val != nil {
|
||||||
conf.NetInterface, _ = args["--interface"].(string)
|
conf.NetInterface, _ = args["--interface"].(string)
|
||||||
}
|
}
|
||||||
if val, _ := args["--extensions"]; val != nil {
|
|
||||||
exs, _ := args["--extensions"].(string)
|
|
||||||
conf.Extensions = strings.Split(exs, ",")
|
|
||||||
}
|
|
||||||
if val, _ := args["--test"]; val != nil {
|
if val, _ := args["--test"]; val != nil {
|
||||||
conf.Test = val.(bool)
|
conf.Test = val.(bool)
|
||||||
}
|
}
|
||||||
|
@ -189,16 +160,35 @@ Log files are stored in %s
|
||||||
if args["--mbps"].(bool) {
|
if args["--mbps"].(bool) {
|
||||||
conf.Mbps = true
|
conf.Mbps = true
|
||||||
}
|
}
|
||||||
if args["--print-paths"].(bool) {
|
if val, _ := args["--list"]; val != nil {
|
||||||
paths := make([]string, 0)
|
switch val {
|
||||||
for _, d := range conf.ConfigDir.QueryFolders(configdir.All) {
|
case "layouts":
|
||||||
paths = append(paths, d.Path)
|
fmt.Println("Built-in layouts:")
|
||||||
}
|
fmt.Println("\tdefault")
|
||||||
fmt.Println(strings.Join(paths, "\n"))
|
fmt.Println("\tminimal")
|
||||||
os.Exit(0)
|
fmt.Println("\tbattery")
|
||||||
}
|
fmt.Println("\tkitchensink")
|
||||||
if args["--print-keys"].(bool) {
|
case "colorschemes":
|
||||||
fmt.Println(`
|
fmt.Println("Built-in colorschemes:")
|
||||||
|
fmt.Println("\tdefault")
|
||||||
|
fmt.Println("\tdefault-dark (for white background)")
|
||||||
|
fmt.Println("\tsolarized")
|
||||||
|
fmt.Println("\tsolarized16-dark")
|
||||||
|
fmt.Println("\tsolarized16-light")
|
||||||
|
fmt.Println("\tmonokai")
|
||||||
|
fmt.Println("\tvice")
|
||||||
|
case "paths":
|
||||||
|
fmt.Println("Loadable colorschemes & layouts, and the config file, are searched for, in order:")
|
||||||
|
paths := make([]string, 0)
|
||||||
|
for _, d := range conf.ConfigDir.QueryFolders(configdir.All) {
|
||||||
|
paths = append(paths, d.Path)
|
||||||
|
}
|
||||||
|
fmt.Println(strings.Join(paths, "\n"))
|
||||||
|
fmt.Printf("\nThe log file is in %s\n", filepath.Join(conf.ConfigDir.QueryCacheFolder().Path, logging.LOGFILE))
|
||||||
|
case "devices":
|
||||||
|
listDevices()
|
||||||
|
case "keys":
|
||||||
|
fmt.Println(`
|
||||||
Quit: q or <C-c>
|
Quit: q or <C-c>
|
||||||
Process navigation:
|
Process navigation:
|
||||||
k and <Up>: up
|
k and <Up>: up
|
||||||
|
@ -227,6 +217,19 @@ CPU and Mem graph scaling:
|
||||||
h: scale in
|
h: scale in
|
||||||
l: scale out
|
l: scale out
|
||||||
?: toggles keybind help menu`)
|
?: toggles keybind help menu`)
|
||||||
|
default:
|
||||||
|
fmt.Printf("Unknown option \"%s\"; try layouts, colorschemes, or devices\n", val)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
if args["--write-config"].(bool) {
|
||||||
|
path, err := conf.Write()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Failed to write configuration file: %s\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
fmt.Printf("Config written to %s\n", path)
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -437,9 +440,11 @@ func makeConfig() gotop.Config {
|
||||||
MaxLogSize: 5000000,
|
MaxLogSize: 5000000,
|
||||||
Layout: "default",
|
Layout: "default",
|
||||||
}
|
}
|
||||||
|
conf.Colorscheme, _ = colorschemes.FromName(conf.ConfigDir, "default")
|
||||||
return conf
|
return conf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Add fans
|
||||||
// TODO: mpd visualizer widget
|
// TODO: mpd visualizer widget
|
||||||
func main() {
|
func main() {
|
||||||
// This is just to make sure gotop returns a useful exit code, but also
|
// This is just to make sure gotop returns a useful exit code, but also
|
||||||
|
@ -567,3 +572,14 @@ func runTests(conf gotop.Config) int {
|
||||||
fmt.Printf("PASS")
|
fmt.Printf("PASS")
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func listDevices() {
|
||||||
|
ms := devices.Domains
|
||||||
|
sort.Strings(ms)
|
||||||
|
for _, m := range ms {
|
||||||
|
fmt.Printf("%s:\n", m)
|
||||||
|
for _, d := range devices.Devices(m) {
|
||||||
|
fmt.Printf("\t%s\n", d)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ func register(name string, c Colorscheme) {
|
||||||
if registry == nil {
|
if registry == nil {
|
||||||
registry = make(map[string]Colorscheme)
|
registry = make(map[string]Colorscheme)
|
||||||
}
|
}
|
||||||
|
c.Name = name
|
||||||
registry[name] = c
|
registry[name] = c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
103
config.go
103
config.go
|
@ -2,10 +2,10 @@ package gotop
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -15,7 +15,6 @@ import (
|
||||||
"github.com/xxxserxxx/gotop/v3/widgets"
|
"github.com/xxxserxxx/gotop/v3/widgets"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: test, build, release [#119] [#120] [#121]
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
ConfigDir configdir.ConfigDir
|
ConfigDir configdir.ConfigDir
|
||||||
|
|
||||||
|
@ -32,30 +31,31 @@ type Config struct {
|
||||||
Layout string
|
Layout string
|
||||||
MaxLogSize int64
|
MaxLogSize int64
|
||||||
ExportPort string
|
ExportPort string
|
||||||
Extensions []string
|
|
||||||
Mbps bool
|
Mbps bool
|
||||||
|
Temps []string
|
||||||
|
|
||||||
Test bool
|
Test bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (conf *Config) Load() error {
|
func (conf *Config) Load() error {
|
||||||
var in io.Reader
|
var in []byte
|
||||||
|
var err error
|
||||||
cfn := "gotop.conf"
|
cfn := "gotop.conf"
|
||||||
folder := conf.ConfigDir.QueryFolderContainsFile(cfn)
|
folder := conf.ConfigDir.QueryFolderContainsFile(cfn)
|
||||||
if folder != nil {
|
if folder != nil {
|
||||||
// FIXME: Shouldn't this be looking in folder??
|
if in, err = folder.ReadFile(cfn); err != nil {
|
||||||
if cf, err := os.Open(cfn); err == nil {
|
|
||||||
defer cf.Close()
|
|
||||||
} else {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
r := bufio.NewScanner(in)
|
r := bufio.NewScanner(bytes.NewReader(in))
|
||||||
var lineNo int
|
var lineNo int
|
||||||
for r.Scan() {
|
for r.Scan() {
|
||||||
l := strings.TrimSpace(r.Text())
|
l := strings.TrimSpace(r.Text())
|
||||||
|
if l[0] == '#' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
kv := strings.Split(l, "=")
|
kv := strings.Split(l, "=")
|
||||||
if len(kv) != 2 {
|
if len(kv) != 2 {
|
||||||
return fmt.Errorf("bad config file syntax; should be KEY=VALUE, was %s", l)
|
return fmt.Errorf("bad config file syntax; should be KEY=VALUE, was %s", l)
|
||||||
|
@ -70,72 +70,125 @@ func (conf *Config) Load() error {
|
||||||
log.Printf("logdir is deprecated. Ignored logdir=%s", kv[1])
|
log.Printf("logdir is deprecated. Ignored logdir=%s", kv[1])
|
||||||
case "logfile":
|
case "logfile":
|
||||||
log.Printf("logfile is deprecated. Ignored logfile=%s", kv[1])
|
log.Printf("logfile is deprecated. Ignored logfile=%s", kv[1])
|
||||||
case "graphhorizontalscale":
|
case graphhorizontalscale:
|
||||||
iv, err := strconv.Atoi(kv[1])
|
iv, err := strconv.Atoi(kv[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
conf.GraphHorizontalScale = iv
|
conf.GraphHorizontalScale = iv
|
||||||
case "helpvisible":
|
case helpvisible:
|
||||||
bv, err := strconv.ParseBool(kv[1])
|
bv, err := strconv.ParseBool(kv[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("line %d: %v", lineNo, err)
|
return fmt.Errorf("line %d: %v", lineNo, err)
|
||||||
}
|
}
|
||||||
conf.HelpVisible = bv
|
conf.HelpVisible = bv
|
||||||
case "colorscheme":
|
case colorscheme:
|
||||||
cs, err := colorschemes.FromName(conf.ConfigDir, kv[1])
|
cs, err := colorschemes.FromName(conf.ConfigDir, kv[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("line %d: %v", lineNo, err)
|
return fmt.Errorf("line %d: %v", lineNo, err)
|
||||||
}
|
}
|
||||||
conf.Colorscheme = cs
|
conf.Colorscheme = cs
|
||||||
case "updateinterval":
|
case updateinterval:
|
||||||
iv, err := strconv.Atoi(kv[1])
|
iv, err := strconv.Atoi(kv[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
conf.UpdateInterval = time.Duration(iv)
|
conf.UpdateInterval = time.Duration(iv)
|
||||||
case "averagecpu":
|
case averagecpu:
|
||||||
bv, err := strconv.ParseBool(kv[1])
|
bv, err := strconv.ParseBool(kv[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("line %d: %v", lineNo, err)
|
return fmt.Errorf("line %d: %v", lineNo, err)
|
||||||
}
|
}
|
||||||
conf.AverageLoad = bv
|
conf.AverageLoad = bv
|
||||||
case "percpuload":
|
case percpuload:
|
||||||
bv, err := strconv.ParseBool(kv[1])
|
bv, err := strconv.ParseBool(kv[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("line %d: %v", lineNo, err)
|
return fmt.Errorf("line %d: %v", lineNo, err)
|
||||||
}
|
}
|
||||||
conf.PercpuLoad = bv
|
conf.PercpuLoad = bv
|
||||||
case "tempscale":
|
case tempscale:
|
||||||
iv, err := strconv.Atoi(kv[1])
|
iv, err := strconv.Atoi(kv[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
conf.TempScale = widgets.TempScale(iv)
|
conf.TempScale = widgets.TempScale(iv)
|
||||||
case "statusbar":
|
case statusbar:
|
||||||
bv, err := strconv.ParseBool(kv[1])
|
bv, err := strconv.ParseBool(kv[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("line %d: %v", lineNo, err)
|
return fmt.Errorf("line %d: %v", lineNo, err)
|
||||||
}
|
}
|
||||||
conf.Statusbar = bv
|
conf.Statusbar = bv
|
||||||
case "netinterface":
|
case netinterface:
|
||||||
conf.NetInterface = kv[1]
|
conf.NetInterface = kv[1]
|
||||||
case "layout":
|
case layout:
|
||||||
conf.Layout = kv[1]
|
conf.Layout = kv[1]
|
||||||
case "maxlogsize":
|
case maxlogsize:
|
||||||
iv, err := strconv.Atoi(kv[1])
|
iv, err := strconv.Atoi(kv[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
conf.MaxLogSize = int64(iv)
|
conf.MaxLogSize = int64(iv)
|
||||||
case "export":
|
case export:
|
||||||
conf.ExportPort = kv[1]
|
conf.ExportPort = kv[1]
|
||||||
case "extensions":
|
case mbps:
|
||||||
conf.Extensions = strings.Split(kv[1], ",")
|
|
||||||
case "mbps":
|
|
||||||
conf.Mbps = true
|
conf.Mbps = true
|
||||||
|
case temperatures:
|
||||||
|
conf.Temps = strings.Split(kv[1], ",")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Config) Write() (string, error) {
|
||||||
|
cfn := "gotop.conf"
|
||||||
|
ds := c.ConfigDir.QueryFolders(configdir.Global)
|
||||||
|
if len(ds) == 0 {
|
||||||
|
ds = c.ConfigDir.QueryFolders(configdir.Local)
|
||||||
|
if len(ds) == 0 {
|
||||||
|
return "", fmt.Errorf("error locating config folders")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
marshalled := marshal(c)
|
||||||
|
err := ds[0].WriteFile(cfn, marshalled)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return filepath.Join(ds[0].Path, cfn), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshal(c *Config) []byte {
|
||||||
|
buff := bytes.NewBuffer(nil)
|
||||||
|
fmt.Fprintf(buff, "%s=%d\n", graphhorizontalscale, c.GraphHorizontalScale)
|
||||||
|
fmt.Fprintf(buff, "%s=%t\n", helpvisible, c.HelpVisible)
|
||||||
|
fmt.Fprintf(buff, "%s=%s\n", colorscheme, c.Colorscheme.Name)
|
||||||
|
fmt.Fprintf(buff, "%s=%d\n", updateinterval, c.UpdateInterval)
|
||||||
|
fmt.Fprintf(buff, "%s=%t\n", averagecpu, c.AverageLoad)
|
||||||
|
fmt.Fprintf(buff, "%s=%t\n", percpuload, c.PercpuLoad)
|
||||||
|
fmt.Fprintf(buff, "%s=%d\n", tempscale, c.TempScale)
|
||||||
|
fmt.Fprintf(buff, "%s=%t\n", statusbar, c.Statusbar)
|
||||||
|
fmt.Fprintf(buff, "%s=%s\n", netinterface, c.NetInterface)
|
||||||
|
fmt.Fprintf(buff, "%s=%s\n", layout, c.Layout)
|
||||||
|
fmt.Fprintf(buff, "%s=%d\n", maxlogsize, c.MaxLogSize)
|
||||||
|
fmt.Fprintf(buff, "%s=%s\n", export, c.ExportPort)
|
||||||
|
fmt.Fprintf(buff, "%s=%t\n", mbps, c.Mbps)
|
||||||
|
fmt.Fprintf(buff, "%s=%s\n", temperatures, strings.Join(c.Temps, ","))
|
||||||
|
return buff.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
graphhorizontalscale = "graphhorizontalscale"
|
||||||
|
helpvisible = "helpvisible"
|
||||||
|
colorscheme = "colorscheme"
|
||||||
|
updateinterval = "updateinterval"
|
||||||
|
averagecpu = "averagecpu"
|
||||||
|
percpuload = "percpuload"
|
||||||
|
tempscale = "tempscale"
|
||||||
|
statusbar = "statusbar"
|
||||||
|
netinterface = "netinterface"
|
||||||
|
layout = "layout"
|
||||||
|
maxlogsize = "maxlogsize"
|
||||||
|
export = "metricsexportport"
|
||||||
|
mbps = "mbps"
|
||||||
|
temperatures = "temperatures"
|
||||||
|
)
|
||||||
|
|
|
@ -2,7 +2,13 @@ package devices
|
||||||
|
|
||||||
import "log"
|
import "log"
|
||||||
|
|
||||||
|
const (
|
||||||
|
Temperatures = "Temperatures"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Domains []string = []string{Temperatures}
|
||||||
var shutdownFuncs []func() error
|
var shutdownFuncs []func() error
|
||||||
|
var _devs map[string][]string
|
||||||
|
|
||||||
// RegisterShutdown stores a function to be called by gotop on exit, allowing
|
// RegisterShutdown stores a function to be called by gotop on exit, allowing
|
||||||
// extensions to properly release resources. Extensions should register a
|
// extensions to properly release resources. Extensions should register a
|
||||||
|
@ -24,3 +30,18 @@ func Shutdown() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RegisterDeviceList(typ string, f func() []string) {
|
||||||
|
if _devs == nil {
|
||||||
|
_devs = make(map[string][]string)
|
||||||
|
}
|
||||||
|
if ls, ok := _devs[typ]; ok {
|
||||||
|
_devs[typ] = append(ls, f()...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_devs[typ] = f()
|
||||||
|
}
|
||||||
|
|
||||||
|
func Devices(domain string) []string {
|
||||||
|
return _devs[domain]
|
||||||
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import smc "github.com/xxxserxxx/iSMC"
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
RegisterTemp(update)
|
RegisterTemp(update)
|
||||||
|
RegisterDeviceList(Temperatures, devs)
|
||||||
ts = make(map[string]float32)
|
ts = make(map[string]float32)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +18,19 @@ func update(temps map[string]int) map[string]error {
|
||||||
return map[string]error{"temps": err}
|
return map[string]error{"temps": err}
|
||||||
}
|
}
|
||||||
for k, v := range ts {
|
for k, v := range ts {
|
||||||
temps[k] = int(v + 0.5)
|
if _, ok := temps[k]; ok {
|
||||||
|
temps[k] = int(v + 0.5)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Set reasonable default devices
|
||||||
|
// CPU (TC[01]P), GPU (TG0P), Memory (Ts0S) and Disk (TH0P)
|
||||||
|
func devs() []string {
|
||||||
|
rv := make([]string, len(smc.AppleTemp))
|
||||||
|
for i, v := range smc.AppleTemp {
|
||||||
|
rv[i] = v.Desc
|
||||||
|
}
|
||||||
|
return rv
|
||||||
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
RegisterTemp(update)
|
RegisterTemp(update)
|
||||||
|
RegisterDeviceList(Temperatures, devs)
|
||||||
}
|
}
|
||||||
|
|
||||||
var sensorOIDS = map[string]string{
|
var sensorOIDS = map[string]string{
|
||||||
|
@ -23,6 +24,9 @@ func update(temps map[string]int) map[string]error {
|
||||||
var errors map[string]error
|
var errors map[string]error
|
||||||
|
|
||||||
for k, v := range sensorOIDS {
|
for k, v := range sensorOIDS {
|
||||||
|
if _, ok := temps[k]; !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
output, err := exec.Command("sysctl", "-n", k).Output()
|
output, err := exec.Command("sysctl", "-n", k).Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors[v] = err
|
errors[v] = err
|
||||||
|
@ -43,3 +47,11 @@ func update(temps map[string]int) map[string]error {
|
||||||
|
|
||||||
return errors
|
return errors
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func devs() []string {
|
||||||
|
rv := make([]string, 0, len(sensorOIDS))
|
||||||
|
for k, _ := range sensorOIDS {
|
||||||
|
rv = append(rv, k)
|
||||||
|
}
|
||||||
|
return rv
|
||||||
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
RegisterTemp(getTemps)
|
RegisterTemp(getTemps)
|
||||||
|
RegisterDeviceList(Temperatures, devs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTemps(temps map[string]int) map[string]error {
|
func getTemps(temps map[string]int) map[string]error {
|
||||||
|
@ -18,12 +19,31 @@ func getTemps(temps map[string]int) map[string]error {
|
||||||
return map[string]error{"psHost": err}
|
return map[string]error{"psHost": err}
|
||||||
}
|
}
|
||||||
for _, sensor := range sensors {
|
for _, sensor := range sensors {
|
||||||
// only sensors with input in their name are giving us live temp info
|
// removes '_input' from the end of the sensor name
|
||||||
if strings.Contains(sensor.SensorKey, "input") && sensor.Temperature != 0 {
|
idx := strings.Index(sensor.SensorKey, "_input")
|
||||||
// removes '_input' from the end of the sensor name
|
if idx >= 0 {
|
||||||
label := sensor.SensorKey[:strings.Index(sensor.SensorKey, "_input")]
|
label := sensor.SensorKey[:idx]
|
||||||
temps[label] = int(sensor.Temperature)
|
if _, ok := temps[label]; ok {
|
||||||
|
temps[label] = int(sensor.Temperature)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func devs() []string {
|
||||||
|
sensors, err := psHost.SensorsTemperatures()
|
||||||
|
if err != nil {
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
rv := make([]string, 0, len(sensors))
|
||||||
|
for _, sensor := range sensors {
|
||||||
|
// only sensors with input in their name are giving us live temp info
|
||||||
|
if strings.Contains(sensor.SensorKey, "input") && sensor.Temperature != 0 {
|
||||||
|
// removes '_input' from the end of the sensor name
|
||||||
|
label := sensor.SensorKey[:strings.Index(sensor.SensorKey, "_input")]
|
||||||
|
rv = append(rv, label)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rv
|
||||||
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TODO: Add filtering. Getting the temperature sensor names is non-trivial for OpenBSD, and until I can test it, leave it unimplemented
|
||||||
func init() {
|
func init() {
|
||||||
RegisterTemp(update)
|
RegisterTemp(update)
|
||||||
}
|
}
|
||||||
|
@ -66,7 +67,9 @@ func getTemp(temps map[string]int, mib []C.int, mlen int, snsrdev *C.struct_sens
|
||||||
key := C.GoString(&snsrdev.xname[0]) + ".temp" + strconv.Itoa(index)
|
key := C.GoString(&snsrdev.xname[0]) + ".temp" + strconv.Itoa(index)
|
||||||
temp := int((snsr.value - 273150000.0) / 1000000.0)
|
temp := int((snsr.value - 273150000.0) / 1000000.0)
|
||||||
|
|
||||||
temps[key] = temp
|
if _, ok := temps[key]; ok {
|
||||||
|
temps[key] = temp
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
RegisterTemp(update)
|
RegisterTemp(update)
|
||||||
|
RegisterDeviceList(Temperatures, devs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func update(temps map[string]int) map[string]error {
|
func update(temps map[string]int) map[string]error {
|
||||||
|
@ -16,9 +17,23 @@ func update(temps map[string]int) map[string]error {
|
||||||
return map[string]error{"gopsutil": err}
|
return map[string]error{"gopsutil": err}
|
||||||
}
|
}
|
||||||
for _, sensor := range sensors {
|
for _, sensor := range sensors {
|
||||||
if sensor.Temperature != 0 {
|
if _, ok := temps[sensor.SensorKey]; ok {
|
||||||
temps[sensor.SensorKey] = int(sensor.Temperature)
|
temps[sensor.SensorKey] = int(sensor.Temperature + 0.5)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func devs() []string {
|
||||||
|
sensors, err := psHost.SensorsTemperatures()
|
||||||
|
if err != nil {
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
rv := make([]string, 0, len(sensors))
|
||||||
|
for _, sensor := range sensors {
|
||||||
|
if sensor.Temperature != 0 {
|
||||||
|
rv = append(rv, sensor.SensorKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rv
|
||||||
|
}
|
||||||
|
|
|
@ -177,7 +177,7 @@ func makeWidget(c gotop.Config, widRule widgetRule) interface{} {
|
||||||
assignColors(b.Data, c.Colorscheme.BattLines, b.LineColors)
|
assignColors(b.Data, c.Colorscheme.BattLines, b.LineColors)
|
||||||
w = b
|
w = b
|
||||||
case "temp":
|
case "temp":
|
||||||
t := widgets.NewTempWidget(c.TempScale)
|
t := widgets.NewTempWidget(c.TempScale, c.Temps)
|
||||||
t.TempLowColor = ui.Color(c.Colorscheme.TempLow)
|
t.TempLowColor = ui.Color(c.Colorscheme.TempLow)
|
||||||
t.TempHighColor = ui.Color(c.Colorscheme.TempHigh)
|
t.TempHighColor = ui.Color(c.Colorscheme.TempHigh)
|
||||||
w = t
|
w = t
|
||||||
|
|
|
@ -32,6 +32,8 @@ type DiskWidget struct {
|
||||||
metric map[string]prometheus.Gauge
|
metric map[string]prometheus.Gauge
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Add filtering
|
||||||
|
// TODO: Abstract out device from widget
|
||||||
func NewDiskWidget() *DiskWidget {
|
func NewDiskWidget() *DiskWidget {
|
||||||
self := &DiskWidget{
|
self := &DiskWidget{
|
||||||
Table: ui.NewTable(),
|
Table: ui.NewTable(),
|
||||||
|
|
|
@ -32,7 +32,7 @@ type TempWidget struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: state:deferred 156 Added temperatures for NVidia GPUs (azak-azkaran/master). Crashes on non-nvidia machines.
|
// TODO: state:deferred 156 Added temperatures for NVidia GPUs (azak-azkaran/master). Crashes on non-nvidia machines.
|
||||||
func NewTempWidget(tempScale TempScale) *TempWidget {
|
func NewTempWidget(tempScale TempScale, filter []string) *TempWidget {
|
||||||
self := &TempWidget{
|
self := &TempWidget{
|
||||||
Block: ui.NewBlock(),
|
Block: ui.NewBlock(),
|
||||||
updateInterval: time.Second * 5,
|
updateInterval: time.Second * 5,
|
||||||
|
@ -41,6 +41,15 @@ func NewTempWidget(tempScale TempScale) *TempWidget {
|
||||||
TempScale: tempScale,
|
TempScale: tempScale,
|
||||||
}
|
}
|
||||||
self.Title = " Temperatures "
|
self.Title = " Temperatures "
|
||||||
|
if len(filter) > 0 {
|
||||||
|
for _, t := range filter {
|
||||||
|
self.Data[t] = 0
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, t := range devices.Devices(devices.Temperatures) {
|
||||||
|
self.Data[t] = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if tempScale == Fahrenheit {
|
if tempScale == Fahrenheit {
|
||||||
self.TempThreshold = utils.CelsiusToFahrenheit(self.TempThreshold)
|
self.TempThreshold = utils.CelsiusToFahrenheit(self.TempThreshold)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user