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
|
||||
event-type: my-release
|
||||
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.
|
||||
- Instructions for Gentoo (thanks @tormath1!)
|
||||
- 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
|
||||
|
||||
|
@ -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)
|
||||
- The disk code was truncating values instead of rounding (#90)
|
||||
- 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
|
||||
|
||||
|
|
61
README.md
61
README.md
|
@ -127,12 +127,30 @@ Move `gotop` to somewhere in your `$PATH`.
|
|||
- click to select process
|
||||
- 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
|
||||
|
||||
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 list all built-in color schemes, call:
|
||||
|
||||
```
|
||||
gotop --list colorschemes
|
||||
```
|
||||
|
||||
### Layouts
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
Run `gotop -h` to see the list of all command line options.
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
@ -20,6 +21,7 @@ import (
|
|||
|
||||
"github.com/xxxserxxx/gotop/v3"
|
||||
"github.com/xxxserxxx/gotop/v3/colorschemes"
|
||||
"github.com/xxxserxxx/gotop/v3/devices"
|
||||
"github.com/xxxserxxx/gotop/v3/layout"
|
||||
"github.com/xxxserxxx/gotop/v3/logging"
|
||||
w "github.com/xxxserxxx/gotop/v3/widgets"
|
||||
|
@ -37,8 +39,8 @@ const (
|
|||
)
|
||||
|
||||
var (
|
||||
// TODO: Set this at compile time; having to check this in sucks.
|
||||
Version = "3.6.dev"
|
||||
Version = "0.0.0"
|
||||
BuildDate = "Hadean"
|
||||
conf gotop.Config
|
||||
help *w.HelpMenu
|
||||
bar *w.StatusBar
|
||||
|
@ -48,17 +50,14 @@ var (
|
|||
|
||||
// TODO: Add tab completion for Linux https://gist.github.com/icholy/5314423
|
||||
// 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: Add fans
|
||||
func parseArgs(conf *gotop.Config) error {
|
||||
cds := conf.ConfigDir.QueryFolders(configdir.All)
|
||||
cpaths := make([]string, len(cds))
|
||||
for i, p := range cds {
|
||||
cpaths[i] = p.Path
|
||||
}
|
||||
usage := fmt.Sprintf(`
|
||||
usage := fmt.Sprintln(`
|
||||
Usage: gotop [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.
|
||||
-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.
|
||||
--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
|
||||
minimal
|
||||
battery
|
||||
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
|
||||
}
|
||||
--list <devices|layouts|colorschemes|paths|keys>
|
||||
devices: Prints out device names for widgets supporting filters.
|
||||
layouts: Lists build-in layouts
|
||||
colorschemes: Lists built-in colorschemes
|
||||
paths: List out the paths that gotop will look for gotop.conf, layouts, and color schemes.
|
||||
keys: Show the keyboard bindings.
|
||||
--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.`)
|
||||
|
||||
args, err := docopt.ParseArgs(usage, os.Args[1:], Version)
|
||||
if err != nil {
|
||||
|
@ -127,6 +101,7 @@ Log files are stored in %s
|
|||
}
|
||||
conf.Colorscheme = cs
|
||||
}
|
||||
|
||||
if args["--averagecpu"].(bool) {
|
||||
conf.AverageLoad, _ = args["--averagecpu"].(bool)
|
||||
}
|
||||
|
@ -166,10 +141,6 @@ Log files are stored in %s
|
|||
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, ",")
|
||||
}
|
||||
if val, _ := args["--test"]; val != nil {
|
||||
conf.Test = val.(bool)
|
||||
}
|
||||
|
@ -189,16 +160,35 @@ Log files are stored in %s
|
|||
if args["--mbps"].(bool) {
|
||||
conf.Mbps = true
|
||||
}
|
||||
if args["--print-paths"].(bool) {
|
||||
paths := make([]string, 0)
|
||||
for _, d := range conf.ConfigDir.QueryFolders(configdir.All) {
|
||||
paths = append(paths, d.Path)
|
||||
}
|
||||
fmt.Println(strings.Join(paths, "\n"))
|
||||
os.Exit(0)
|
||||
}
|
||||
if args["--print-keys"].(bool) {
|
||||
fmt.Println(`
|
||||
if val, _ := args["--list"]; val != nil {
|
||||
switch val {
|
||||
case "layouts":
|
||||
fmt.Println("Built-in layouts:")
|
||||
fmt.Println("\tdefault")
|
||||
fmt.Println("\tminimal")
|
||||
fmt.Println("\tbattery")
|
||||
fmt.Println("\tkitchensink")
|
||||
case "colorschemes":
|
||||
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>
|
||||
Process navigation:
|
||||
k and <Up>: up
|
||||
|
@ -227,6 +217,19 @@ CPU and Mem graph scaling:
|
|||
h: scale in
|
||||
l: scale out
|
||||
?: 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)
|
||||
}
|
||||
|
||||
|
@ -437,9 +440,11 @@ func makeConfig() gotop.Config {
|
|||
MaxLogSize: 5000000,
|
||||
Layout: "default",
|
||||
}
|
||||
conf.Colorscheme, _ = colorschemes.FromName(conf.ConfigDir, "default")
|
||||
return conf
|
||||
}
|
||||
|
||||
// TODO: Add fans
|
||||
// TODO: mpd visualizer widget
|
||||
func main() {
|
||||
// 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")
|
||||
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 {
|
||||
registry = make(map[string]Colorscheme)
|
||||
}
|
||||
c.Name = name
|
||||
registry[name] = c
|
||||
}
|
||||
|
||||
|
|
103
config.go
103
config.go
|
@ -2,10 +2,10 @@ package gotop
|
|||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -15,7 +15,6 @@ import (
|
|||
"github.com/xxxserxxx/gotop/v3/widgets"
|
||||
)
|
||||
|
||||
// TODO: test, build, release [#119] [#120] [#121]
|
||||
type Config struct {
|
||||
ConfigDir configdir.ConfigDir
|
||||
|
||||
|
@ -32,30 +31,31 @@ type Config struct {
|
|||
Layout string
|
||||
MaxLogSize int64
|
||||
ExportPort string
|
||||
Extensions []string
|
||||
Mbps bool
|
||||
Temps []string
|
||||
|
||||
Test bool
|
||||
}
|
||||
|
||||
func (conf *Config) Load() error {
|
||||
var in io.Reader
|
||||
var in []byte
|
||||
var err error
|
||||
cfn := "gotop.conf"
|
||||
folder := conf.ConfigDir.QueryFolderContainsFile(cfn)
|
||||
if folder != nil {
|
||||
// FIXME: Shouldn't this be looking in folder??
|
||||
if cf, err := os.Open(cfn); err == nil {
|
||||
defer cf.Close()
|
||||
} else {
|
||||
if in, err = folder.ReadFile(cfn); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
r := bufio.NewScanner(in)
|
||||
r := bufio.NewScanner(bytes.NewReader(in))
|
||||
var lineNo int
|
||||
for r.Scan() {
|
||||
l := strings.TrimSpace(r.Text())
|
||||
if l[0] == '#' {
|
||||
continue
|
||||
}
|
||||
kv := strings.Split(l, "=")
|
||||
if len(kv) != 2 {
|
||||
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])
|
||||
case "logfile":
|
||||
log.Printf("logfile is deprecated. Ignored logfile=%s", kv[1])
|
||||
case "graphhorizontalscale":
|
||||
case graphhorizontalscale:
|
||||
iv, err := strconv.Atoi(kv[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
conf.GraphHorizontalScale = iv
|
||||
case "helpvisible":
|
||||
case helpvisible:
|
||||
bv, err := strconv.ParseBool(kv[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("line %d: %v", lineNo, err)
|
||||
}
|
||||
conf.HelpVisible = bv
|
||||
case "colorscheme":
|
||||
case colorscheme:
|
||||
cs, err := colorschemes.FromName(conf.ConfigDir, kv[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("line %d: %v", lineNo, err)
|
||||
}
|
||||
conf.Colorscheme = cs
|
||||
case "updateinterval":
|
||||
case updateinterval:
|
||||
iv, err := strconv.Atoi(kv[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
conf.UpdateInterval = time.Duration(iv)
|
||||
case "averagecpu":
|
||||
case averagecpu:
|
||||
bv, err := strconv.ParseBool(kv[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("line %d: %v", lineNo, err)
|
||||
}
|
||||
conf.AverageLoad = bv
|
||||
case "percpuload":
|
||||
case percpuload:
|
||||
bv, err := strconv.ParseBool(kv[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("line %d: %v", lineNo, err)
|
||||
}
|
||||
conf.PercpuLoad = bv
|
||||
case "tempscale":
|
||||
case tempscale:
|
||||
iv, err := strconv.Atoi(kv[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
conf.TempScale = widgets.TempScale(iv)
|
||||
case "statusbar":
|
||||
case statusbar:
|
||||
bv, err := strconv.ParseBool(kv[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("line %d: %v", lineNo, err)
|
||||
}
|
||||
conf.Statusbar = bv
|
||||
case "netinterface":
|
||||
case netinterface:
|
||||
conf.NetInterface = kv[1]
|
||||
case "layout":
|
||||
case layout:
|
||||
conf.Layout = kv[1]
|
||||
case "maxlogsize":
|
||||
case maxlogsize:
|
||||
iv, err := strconv.Atoi(kv[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
conf.MaxLogSize = int64(iv)
|
||||
case "export":
|
||||
case export:
|
||||
conf.ExportPort = kv[1]
|
||||
case "extensions":
|
||||
conf.Extensions = strings.Split(kv[1], ",")
|
||||
case "mbps":
|
||||
case mbps:
|
||||
conf.Mbps = true
|
||||
case temperatures:
|
||||
conf.Temps = strings.Split(kv[1], ",")
|
||||
}
|
||||
}
|
||||
|
||||
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"
|
||||
|
||||
const (
|
||||
Temperatures = "Temperatures"
|
||||
)
|
||||
|
||||
var Domains []string = []string{Temperatures}
|
||||
var shutdownFuncs []func() error
|
||||
var _devs map[string][]string
|
||||
|
||||
// RegisterShutdown stores a function to be called by gotop on exit, allowing
|
||||
// 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() {
|
||||
RegisterTemp(update)
|
||||
RegisterDeviceList(Temperatures, devs)
|
||||
ts = make(map[string]float32)
|
||||
}
|
||||
|
||||
|
@ -17,7 +18,19 @@ func update(temps map[string]int) map[string]error {
|
|||
return map[string]error{"temps": err}
|
||||
}
|
||||
for k, v := range ts {
|
||||
temps[k] = int(v + 0.5)
|
||||
if _, ok := temps[k]; ok {
|
||||
temps[k] = int(v + 0.5)
|
||||
}
|
||||
}
|
||||
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() {
|
||||
RegisterTemp(update)
|
||||
RegisterDeviceList(Temperatures, devs)
|
||||
}
|
||||
|
||||
var sensorOIDS = map[string]string{
|
||||
|
@ -23,6 +24,9 @@ func update(temps map[string]int) map[string]error {
|
|||
var errors map[string]error
|
||||
|
||||
for k, v := range sensorOIDS {
|
||||
if _, ok := temps[k]; !ok {
|
||||
continue
|
||||
}
|
||||
output, err := exec.Command("sysctl", "-n", k).Output()
|
||||
if err != nil {
|
||||
errors[v] = err
|
||||
|
@ -43,3 +47,11 @@ func update(temps map[string]int) map[string]error {
|
|||
|
||||
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() {
|
||||
RegisterTemp(getTemps)
|
||||
RegisterDeviceList(Temperatures, devs)
|
||||
}
|
||||
|
||||
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}
|
||||
}
|
||||
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")]
|
||||
temps[label] = int(sensor.Temperature)
|
||||
// removes '_input' from the end of the sensor name
|
||||
idx := strings.Index(sensor.SensorKey, "_input")
|
||||
if idx >= 0 {
|
||||
label := sensor.SensorKey[:idx]
|
||||
if _, ok := temps[label]; ok {
|
||||
temps[label] = int(sensor.Temperature)
|
||||
}
|
||||
}
|
||||
}
|
||||
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"
|
||||
)
|
||||
|
||||
// TODO: Add filtering. Getting the temperature sensor names is non-trivial for OpenBSD, and until I can test it, leave it unimplemented
|
||||
func init() {
|
||||
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)
|
||||
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() {
|
||||
RegisterTemp(update)
|
||||
RegisterDeviceList(Temperatures, devs)
|
||||
}
|
||||
|
||||
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}
|
||||
}
|
||||
for _, sensor := range sensors {
|
||||
if sensor.Temperature != 0 {
|
||||
temps[sensor.SensorKey] = int(sensor.Temperature)
|
||||
if _, ok := temps[sensor.SensorKey]; ok {
|
||||
temps[sensor.SensorKey] = int(sensor.Temperature + 0.5)
|
||||
}
|
||||
}
|
||||
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)
|
||||
w = b
|
||||
case "temp":
|
||||
t := widgets.NewTempWidget(c.TempScale)
|
||||
t := widgets.NewTempWidget(c.TempScale, c.Temps)
|
||||
t.TempLowColor = ui.Color(c.Colorscheme.TempLow)
|
||||
t.TempHighColor = ui.Color(c.Colorscheme.TempHigh)
|
||||
w = t
|
||||
|
|
|
@ -32,6 +32,8 @@ type DiskWidget struct {
|
|||
metric map[string]prometheus.Gauge
|
||||
}
|
||||
|
||||
// TODO: Add filtering
|
||||
// TODO: Abstract out device from widget
|
||||
func NewDiskWidget() *DiskWidget {
|
||||
self := &DiskWidget{
|
||||
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.
|
||||
func NewTempWidget(tempScale TempScale) *TempWidget {
|
||||
func NewTempWidget(tempScale TempScale, filter []string) *TempWidget {
|
||||
self := &TempWidget{
|
||||
Block: ui.NewBlock(),
|
||||
updateInterval: time.Second * 5,
|
||||
|
@ -41,6 +41,15 @@ func NewTempWidget(tempScale TempScale) *TempWidget {
|
|||
TempScale: tempScale,
|
||||
}
|
||||
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 {
|
||||
self.TempThreshold = utils.CelsiusToFahrenheit(self.TempThreshold)
|
||||
|
|
Loading…
Reference in New Issue
Block a user