Go vet/lint cleanups
This commit is contained in:
parent
1e78e6faa0
commit
285d4d0297
|
@ -25,6 +25,7 @@ import (
|
||||||
"github.com/xxxserxxx/gotop/v4/devices"
|
"github.com/xxxserxxx/gotop/v4/devices"
|
||||||
"github.com/xxxserxxx/gotop/v4/layout"
|
"github.com/xxxserxxx/gotop/v4/layout"
|
||||||
"github.com/xxxserxxx/gotop/v4/logging"
|
"github.com/xxxserxxx/gotop/v4/logging"
|
||||||
|
"github.com/xxxserxxx/gotop/v4/widgets"
|
||||||
w "github.com/xxxserxxx/gotop/v4/widgets"
|
w "github.com/xxxserxxx/gotop/v4/widgets"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -38,7 +39,9 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
Version = "0.0.0"
|
// Version of the program; set during build from git tags
|
||||||
|
Version = "0.0.0"
|
||||||
|
// BuildDate when the program was compiled; set during build
|
||||||
BuildDate = "Hadean"
|
BuildDate = "Hadean"
|
||||||
conf gotop.Config
|
conf gotop.Config
|
||||||
help *w.HelpMenu
|
help *w.HelpMenu
|
||||||
|
@ -104,9 +107,9 @@ func parseArgs(conf *gotop.Config) error {
|
||||||
if *list != "" {
|
if *list != "" {
|
||||||
switch *list {
|
switch *list {
|
||||||
case "layouts":
|
case "layouts":
|
||||||
fmt.Println(LAYOUTS)
|
fmt.Println(_layouts)
|
||||||
case "colorschemes":
|
case "colorschemes":
|
||||||
fmt.Println(COLORSCHEMES)
|
fmt.Println(_colorschemes)
|
||||||
case "paths":
|
case "paths":
|
||||||
fmt.Println("Loadable colorschemes & layouts, and the config file, are searched for, in order:")
|
fmt.Println("Loadable colorschemes & layouts, and the config file, are searched for, in order:")
|
||||||
paths := make([]string, 0)
|
paths := make([]string, 0)
|
||||||
|
@ -118,7 +121,7 @@ func parseArgs(conf *gotop.Config) error {
|
||||||
case "devices":
|
case "devices":
|
||||||
listDevices()
|
listDevices()
|
||||||
case "keys":
|
case "keys":
|
||||||
fmt.Println(KEYS)
|
fmt.Println(widgets.KEYBINDS)
|
||||||
default:
|
default:
|
||||||
fmt.Printf("Unknown option \"%s\"; try layouts, colorschemes, keys, paths, or devices\n", *list)
|
fmt.Printf("Unknown option \"%s\"; try layouts, colorschemes, keys, paths, or devices\n", *list)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
@ -391,7 +394,7 @@ func run() int {
|
||||||
}
|
}
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
if err := ui.Init(); err != nil {
|
if err = ui.Init(); err != nil {
|
||||||
stderrLogger.Print(err)
|
stderrLogger.Print(err)
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
@ -481,40 +484,12 @@ func listDevices() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const KEYS = `Quit: q or <C-c>
|
const _layouts = `Built-in layouts:
|
||||||
Process navigation:
|
|
||||||
k and <Up>: up
|
|
||||||
j and <Down>: down
|
|
||||||
<C-u>: half page up
|
|
||||||
<C-d>: half page down
|
|
||||||
<C-b>: full page up
|
|
||||||
<C-f>: full page down
|
|
||||||
gg and <Home>: jump to top
|
|
||||||
G and <End>: jump to bottom
|
|
||||||
Process actions:
|
|
||||||
<Tab>: toggle process grouping
|
|
||||||
dd: kill selected process or group of processes with SIGTERM
|
|
||||||
d3: kill selected process or group of processes with SIGQUIT
|
|
||||||
d9: kill selected process or group of processes with SIGKILL
|
|
||||||
Process sorting
|
|
||||||
c: CPU
|
|
||||||
m: Mem
|
|
||||||
p: PID
|
|
||||||
Process filtering:
|
|
||||||
/: start editing filter
|
|
||||||
(while editing):
|
|
||||||
<Enter> accept filter
|
|
||||||
<C-c> and <Escape>: clear filter
|
|
||||||
CPU and Mem graph scaling:
|
|
||||||
h: scale in
|
|
||||||
l: scale out
|
|
||||||
?: toggles keybind help menu`
|
|
||||||
const LAYOUTS = `Built-in layouts:
|
|
||||||
default
|
default
|
||||||
minimal
|
minimal
|
||||||
battery
|
battery
|
||||||
kitchensink`
|
kitchensink`
|
||||||
const COLORSCHEMES = `Built-in colorschemes:
|
const _colorschemes = `Built-in colorschemes:
|
||||||
default
|
default
|
||||||
default-dark (for white background)
|
default-dark (for white background)
|
||||||
solarized
|
solarized
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package colorschemes
|
package colorschemes
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/shibukawa/configdir"
|
||||||
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
@ -8,8 +10,10 @@ import (
|
||||||
func TestColorRegistry(t *testing.T) {
|
func TestColorRegistry(t *testing.T) {
|
||||||
colors := []string{"default", "default-dark", "solarized", "solarized16-dark", "solarized16-light", "monokai", "vice"}
|
colors := []string{"default", "default-dark", "solarized", "solarized16-dark", "solarized16-light", "monokai", "vice"}
|
||||||
zeroCS := Colorscheme{}
|
zeroCS := Colorscheme{}
|
||||||
|
cd := configdir.New("", "gotop")
|
||||||
|
cd.LocalPath, _ = filepath.Abs(".")
|
||||||
for _, cn := range colors {
|
for _, cn := range colors {
|
||||||
c, e := FromName("", cn)
|
c, e := FromName(cd, cn)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
t.Errorf("unexpected error fetching built-in color %s: %s", cn, e)
|
t.Errorf("unexpected error fetching built-in color %s: %s", cn, e)
|
||||||
}
|
}
|
||||||
|
|
10
config.go
10
config.go
|
@ -48,7 +48,7 @@ func NewConfig() Config {
|
||||||
PercpuLoad: true,
|
PercpuLoad: true,
|
||||||
TempScale: widgets.Celsius,
|
TempScale: widgets.Celsius,
|
||||||
Statusbar: false,
|
Statusbar: false,
|
||||||
NetInterface: widgets.NET_INTERFACE_ALL,
|
NetInterface: widgets.NetInterfaceAll,
|
||||||
MaxLogSize: 5000000,
|
MaxLogSize: 5000000,
|
||||||
Layout: "default",
|
Layout: "default",
|
||||||
ExtensionVars: make(map[string]string),
|
ExtensionVars: make(map[string]string),
|
||||||
|
@ -169,16 +169,16 @@ func load(in io.Reader, conf *Config) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) Write() (string, error) {
|
func (conf *Config) Write() (string, error) {
|
||||||
cfn := "gotop.conf"
|
cfn := "gotop.conf"
|
||||||
ds := c.ConfigDir.QueryFolders(configdir.Global)
|
ds := conf.ConfigDir.QueryFolders(configdir.Global)
|
||||||
if len(ds) == 0 {
|
if len(ds) == 0 {
|
||||||
ds = c.ConfigDir.QueryFolders(configdir.Local)
|
ds = conf.ConfigDir.QueryFolders(configdir.Local)
|
||||||
if len(ds) == 0 {
|
if len(ds) == 0 {
|
||||||
return "", fmt.Errorf("error locating config folders")
|
return "", fmt.Errorf("error locating config folders")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
marshalled := marshal(c)
|
marshalled := marshal(conf)
|
||||||
err := ds[0].WriteFile(cfn, marshalled)
|
err := ds[0].WriteFile(cfn, marshalled)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
|
|
@ -78,7 +78,6 @@ func RegisterDeviceList(typ string, all func() []string, def func() []string) {
|
||||||
func Devices(domain string, all bool) []string {
|
func Devices(domain string, all bool) []string {
|
||||||
if all {
|
if all {
|
||||||
return _devs[domain]
|
return _devs[domain]
|
||||||
} else {
|
|
||||||
return _defaults[domain]
|
|
||||||
}
|
}
|
||||||
|
return _defaults[domain]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
// Copyright 2020 The gotop Authors Licensed under terms of the LICENSE file in this repository.
|
|
||||||
package layout
|
package layout
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -165,7 +164,7 @@ func makeWidget(c gotop.Config, widRule widgetRule) interface{} {
|
||||||
dw := widgets.NewDiskWidget()
|
dw := widgets.NewDiskWidget()
|
||||||
w = dw
|
w = dw
|
||||||
case "cpu":
|
case "cpu":
|
||||||
cpu := widgets.NewCpuWidget(c.UpdateInterval, c.GraphHorizontalScale, c.AverageLoad, c.PercpuLoad)
|
cpu := widgets.NewCPUWidget(c.UpdateInterval, c.GraphHorizontalScale, c.AverageLoad, c.PercpuLoad)
|
||||||
assignColors(cpu.Data, c.Colorscheme.CPULines, cpu.LineColors)
|
assignColors(cpu.Data, c.Colorscheme.CPULines, cpu.LineColors)
|
||||||
w = cpu
|
w = cpu
|
||||||
case "mem":
|
case "mem":
|
||||||
|
@ -228,7 +227,7 @@ func assignColors(data map[string][]float64, colors []int, assign map[string]ui.
|
||||||
func countNumRows(rs [][]widgetRule) int {
|
func countNumRows(rs [][]widgetRule) int {
|
||||||
var ttl int
|
var ttl int
|
||||||
for len(rs) > 0 {
|
for len(rs) > 0 {
|
||||||
ttl += 1
|
ttl++
|
||||||
line := rs[0]
|
line := rs[0]
|
||||||
h := 1
|
h := 1
|
||||||
for _, c := range line {
|
for _, c := range line {
|
||||||
|
|
|
@ -111,7 +111,7 @@ func ParseLayout(i io.Reader) layout {
|
||||||
}
|
}
|
||||||
weightTotal += weight
|
weightTotal += weight
|
||||||
} else {
|
} else {
|
||||||
weightTotal += 1
|
weightTotal++
|
||||||
}
|
}
|
||||||
row = append(row, wr)
|
row = append(row, wr)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,6 @@ func TestLogging(t *testing.T) {
|
||||||
defer os.RemoveAll(path)
|
defer os.RemoveAll(path)
|
||||||
c := gotop.Config{
|
c := gotop.Config{
|
||||||
MaxLogSize: 300,
|
MaxLogSize: 300,
|
||||||
LogDir: path,
|
|
||||||
LogFile: "errors.log",
|
|
||||||
}
|
}
|
||||||
wc, err := New(c)
|
wc, err := New(c)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
@ -27,7 +25,7 @@ func TestLogging(t *testing.T) {
|
||||||
}
|
}
|
||||||
defer wc.Close()
|
defer wc.Close()
|
||||||
ds := make([]byte, 100)
|
ds := make([]byte, 100)
|
||||||
for i, _ := range ds {
|
for i := range ds {
|
||||||
ds[i] = 'x'
|
ds[i] = 'x'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
func ConvertLocalizedString(s string) string {
|
func ConvertLocalizedString(s string) string {
|
||||||
if strings.ContainsAny(s, ",") {
|
if strings.ContainsAny(s, ",") {
|
||||||
return strings.Replace(s, ",", ".", 1)
|
return strings.Replace(s, ",", ".", 1)
|
||||||
} else {
|
|
||||||
return s
|
|
||||||
}
|
}
|
||||||
|
return s
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ func (b *BatteryWidget) EnableMetric() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeId(i int) string {
|
func makeID(i int) string {
|
||||||
return "Batt" + strconv.Itoa(i)
|
return "Batt" + strconv.Itoa(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ func (b *BatteryWidget) Scale(i int) {
|
||||||
b.LineGraph.HorizontalScale = i
|
b.LineGraph.HorizontalScale = i
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *BatteryWidget) update() {
|
func (b *BatteryWidget) update() {
|
||||||
batteries, err := battery.GetAll()
|
batteries, err := battery.GetAll()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
switch errt := err.(type) {
|
switch errt := err.(type) {
|
||||||
|
@ -94,13 +94,13 @@ func (self *BatteryWidget) update() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i, battery := range batteries {
|
for i, battery := range batteries {
|
||||||
id := makeId(i)
|
id := makeID(i)
|
||||||
perc := battery.Current / battery.Full
|
perc := battery.Current / battery.Full
|
||||||
percentFull := math.Abs(perc) * 100.0
|
percentFull := math.Abs(perc) * 100.0
|
||||||
self.Data[id] = append(self.Data[id], percentFull)
|
b.Data[id] = append(b.Data[id], percentFull)
|
||||||
self.Labels[id] = fmt.Sprintf("%3.0f%% %.0f/%.0f", percentFull, math.Abs(battery.Current), math.Abs(battery.Full))
|
b.Labels[id] = fmt.Sprintf("%3.0f%% %.0f/%.0f", percentFull, math.Abs(battery.Current), math.Abs(battery.Full))
|
||||||
if self.metric != nil {
|
if b.metric != nil {
|
||||||
self.metric[i].Set(perc)
|
b.metric[i].Set(perc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,16 +9,16 @@ import (
|
||||||
"github.com/distatus/battery"
|
"github.com/distatus/battery"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
|
||||||
. "github.com/xxxserxxx/gotop/v4/termui"
|
"github.com/xxxserxxx/gotop/v4/termui"
|
||||||
)
|
)
|
||||||
|
|
||||||
type BatteryGauge struct {
|
type BatteryGauge struct {
|
||||||
*Gauge
|
*termui.Gauge
|
||||||
metric prometheus.Gauge
|
metric prometheus.Gauge
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBatteryGauge() *BatteryGauge {
|
func NewBatteryGauge() *BatteryGauge {
|
||||||
self := &BatteryGauge{Gauge: NewGauge()}
|
self := &BatteryGauge{Gauge: termui.NewGauge()}
|
||||||
self.Title = " Power Level "
|
self.Title = " Power Level "
|
||||||
|
|
||||||
self.update()
|
self.update()
|
||||||
|
@ -56,7 +56,7 @@ func (b *BatteryGauge) EnableMetric() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *BatteryGauge) update() {
|
func (b *BatteryGauge) update() {
|
||||||
bats, err := battery.GetAll()
|
bats, err := battery.GetAll()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("error setting up batteries: %v", err)
|
log.Printf("error setting up batteries: %v", err)
|
||||||
|
@ -78,9 +78,9 @@ func (self *BatteryGauge) update() {
|
||||||
}
|
}
|
||||||
tn := (mx - cu) / rate
|
tn := (mx - cu) / rate
|
||||||
d, _ := time.ParseDuration(fmt.Sprintf("%fh", tn))
|
d, _ := time.ParseDuration(fmt.Sprintf("%fh", tn))
|
||||||
self.Percent = int((cu / mx) * 100.0)
|
b.Percent = int((cu / mx) * 100.0)
|
||||||
self.Label = fmt.Sprintf(charging, self.Percent, d.Truncate(time.Minute))
|
b.Label = fmt.Sprintf(charging, b.Percent, d.Truncate(time.Minute))
|
||||||
if self.metric != nil {
|
if b.metric != nil {
|
||||||
self.metric.Set(cu / mx)
|
b.metric.Set(cu / mx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,11 +12,11 @@ import (
|
||||||
ui "github.com/xxxserxxx/gotop/v4/termui"
|
ui "github.com/xxxserxxx/gotop/v4/termui"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CpuWidget struct {
|
type CPUWidget struct {
|
||||||
*ui.LineGraph
|
*ui.LineGraph
|
||||||
CpuCount int
|
CPUCount int
|
||||||
ShowAverageLoad bool
|
ShowAverageLoad bool
|
||||||
ShowPerCpuLoad bool
|
ShowPerCPULoad bool
|
||||||
updateInterval time.Duration
|
updateInterval time.Duration
|
||||||
updateLock sync.Mutex
|
updateLock sync.Mutex
|
||||||
metric map[string]prometheus.Gauge
|
metric map[string]prometheus.Gauge
|
||||||
|
@ -24,20 +24,20 @@ type CpuWidget struct {
|
||||||
|
|
||||||
var cpuLabels []string
|
var cpuLabels []string
|
||||||
|
|
||||||
func NewCpuWidget(updateInterval time.Duration, horizontalScale int, showAverageLoad bool, showPerCpuLoad bool) *CpuWidget {
|
func NewCPUWidget(updateInterval time.Duration, horizontalScale int, showAverageLoad bool, showPerCPULoad bool) *CPUWidget {
|
||||||
self := &CpuWidget{
|
self := &CPUWidget{
|
||||||
LineGraph: ui.NewLineGraph(),
|
LineGraph: ui.NewLineGraph(),
|
||||||
CpuCount: len(cpuLabels),
|
CPUCount: len(cpuLabels),
|
||||||
updateInterval: updateInterval,
|
updateInterval: updateInterval,
|
||||||
ShowAverageLoad: showAverageLoad,
|
ShowAverageLoad: showAverageLoad,
|
||||||
ShowPerCpuLoad: showPerCpuLoad,
|
ShowPerCPULoad: showPerCPULoad,
|
||||||
}
|
}
|
||||||
self.Title = " CPU Usage "
|
self.Title = " CPU Usage "
|
||||||
self.HorizontalScale = horizontalScale
|
self.HorizontalScale = horizontalScale
|
||||||
|
|
||||||
if !(self.ShowAverageLoad || self.ShowPerCpuLoad) {
|
if !(self.ShowAverageLoad || self.ShowPerCPULoad) {
|
||||||
if self.CpuCount <= 8 {
|
if self.CPUCount <= 8 {
|
||||||
self.ShowPerCpuLoad = true
|
self.ShowPerCPULoad = true
|
||||||
} else {
|
} else {
|
||||||
self.ShowAverageLoad = true
|
self.ShowAverageLoad = true
|
||||||
}
|
}
|
||||||
|
@ -47,9 +47,9 @@ func NewCpuWidget(updateInterval time.Duration, horizontalScale int, showAverage
|
||||||
self.Data["AVRG"] = []float64{0}
|
self.Data["AVRG"] = []float64{0}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.ShowPerCpuLoad {
|
if self.ShowPerCPULoad {
|
||||||
cpus := make(map[string]int)
|
cpus := make(map[string]int)
|
||||||
devices.UpdateCPU(cpus, self.updateInterval, self.ShowPerCpuLoad)
|
devices.UpdateCPU(cpus, self.updateInterval, self.ShowPerCPULoad)
|
||||||
for k, v := range cpus {
|
for k, v := range cpus {
|
||||||
self.Data[k] = []float64{float64(v)}
|
self.Data[k] = []float64{float64(v)}
|
||||||
}
|
}
|
||||||
|
@ -66,17 +66,17 @@ func NewCpuWidget(updateInterval time.Duration, horizontalScale int, showAverage
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *CpuWidget) EnableMetric() {
|
func (cpu *CPUWidget) EnableMetric() {
|
||||||
if self.ShowAverageLoad {
|
if cpu.ShowAverageLoad {
|
||||||
self.metric = make(map[string]prometheus.Gauge)
|
cpu.metric = make(map[string]prometheus.Gauge)
|
||||||
self.metric["AVRG"] = prometheus.NewGauge(prometheus.GaugeOpts{
|
cpu.metric["AVRG"] = prometheus.NewGauge(prometheus.GaugeOpts{
|
||||||
Subsystem: "cpu",
|
Subsystem: "cpu",
|
||||||
Name: "avg",
|
Name: "avg",
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
cpus := make(map[string]int)
|
cpus := make(map[string]int)
|
||||||
devices.UpdateCPU(cpus, self.updateInterval, self.ShowPerCpuLoad)
|
devices.UpdateCPU(cpus, cpu.updateInterval, cpu.ShowPerCPULoad)
|
||||||
self.metric = make(map[string]prometheus.Gauge)
|
cpu.metric = make(map[string]prometheus.Gauge)
|
||||||
for key, perc := range cpus {
|
for key, perc := range cpus {
|
||||||
gauge := prometheus.NewGauge(prometheus.GaugeOpts{
|
gauge := prometheus.NewGauge(prometheus.GaugeOpts{
|
||||||
Namespace: "gotop",
|
Namespace: "gotop",
|
||||||
|
@ -85,53 +85,53 @@ func (self *CpuWidget) EnableMetric() {
|
||||||
})
|
})
|
||||||
gauge.Set(float64(perc))
|
gauge.Set(float64(perc))
|
||||||
prometheus.MustRegister(gauge)
|
prometheus.MustRegister(gauge)
|
||||||
self.metric[key] = gauge
|
cpu.metric[key] = gauge
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *CpuWidget) Scale(i int) {
|
func (cpu *CPUWidget) Scale(i int) {
|
||||||
b.LineGraph.HorizontalScale = i
|
cpu.LineGraph.HorizontalScale = i
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *CpuWidget) update() {
|
func (cpu *CPUWidget) update() {
|
||||||
if self.ShowAverageLoad {
|
if cpu.ShowAverageLoad {
|
||||||
go func() {
|
go func() {
|
||||||
cpus := make(map[string]int)
|
cpus := make(map[string]int)
|
||||||
devices.UpdateCPU(cpus, self.updateInterval, false)
|
devices.UpdateCPU(cpus, cpu.updateInterval, false)
|
||||||
self.Lock()
|
cpu.Lock()
|
||||||
defer self.Unlock()
|
defer cpu.Unlock()
|
||||||
self.updateLock.Lock()
|
cpu.updateLock.Lock()
|
||||||
defer self.updateLock.Unlock()
|
defer cpu.updateLock.Unlock()
|
||||||
var val float64
|
var val float64
|
||||||
for _, v := range cpus {
|
for _, v := range cpus {
|
||||||
val = float64(v)
|
val = float64(v)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
self.Data["AVRG"] = append(self.Data["AVRG"], val)
|
cpu.Data["AVRG"] = append(cpu.Data["AVRG"], val)
|
||||||
self.Labels["AVRG"] = fmt.Sprintf("%3.0f%%", val)
|
cpu.Labels["AVRG"] = fmt.Sprintf("%3.0f%%", val)
|
||||||
if self.metric != nil {
|
if cpu.metric != nil {
|
||||||
self.metric["AVRG"].Set(val)
|
cpu.metric["AVRG"].Set(val)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.ShowPerCpuLoad {
|
if cpu.ShowPerCPULoad {
|
||||||
go func() {
|
go func() {
|
||||||
cpus := make(map[string]int)
|
cpus := make(map[string]int)
|
||||||
devices.UpdateCPU(cpus, self.updateInterval, true)
|
devices.UpdateCPU(cpus, cpu.updateInterval, true)
|
||||||
self.Lock()
|
cpu.Lock()
|
||||||
defer self.Unlock()
|
defer cpu.Unlock()
|
||||||
self.updateLock.Lock()
|
cpu.updateLock.Lock()
|
||||||
defer self.updateLock.Unlock()
|
defer cpu.updateLock.Unlock()
|
||||||
for key, percent := range cpus {
|
for key, percent := range cpus {
|
||||||
self.Data[key] = append(self.Data[key], float64(percent))
|
cpu.Data[key] = append(cpu.Data[key], float64(percent))
|
||||||
self.Labels[key] = fmt.Sprintf("%d%%", percent)
|
cpu.Labels[key] = fmt.Sprintf("%d%%", percent)
|
||||||
if self.metric != nil {
|
if cpu.metric != nil {
|
||||||
if self.metric[key] == nil {
|
if cpu.metric[key] == nil {
|
||||||
log.Printf("no metrics for %s", key)
|
log.Printf("no metrics for %s", key)
|
||||||
} else {
|
} else {
|
||||||
self.metric[key].Set(float64(percent))
|
cpu.metric[key].Set(float64(percent))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,9 +64,9 @@ func NewDiskWidget() *DiskWidget {
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *DiskWidget) EnableMetric() {
|
func (disk *DiskWidget) EnableMetric() {
|
||||||
self.metric = make(map[string]prometheus.Gauge)
|
disk.metric = make(map[string]prometheus.Gauge)
|
||||||
for key, part := range self.Partitions {
|
for key, part := range disk.Partitions {
|
||||||
gauge := prometheus.NewGauge(prometheus.GaugeOpts{
|
gauge := prometheus.NewGauge(prometheus.GaugeOpts{
|
||||||
Namespace: "gotop",
|
Namespace: "gotop",
|
||||||
Subsystem: "disk",
|
Subsystem: "disk",
|
||||||
|
@ -75,11 +75,11 @@ func (self *DiskWidget) EnableMetric() {
|
||||||
})
|
})
|
||||||
gauge.Set(float64(part.UsedPercent) / 100.0)
|
gauge.Set(float64(part.UsedPercent) / 100.0)
|
||||||
prometheus.MustRegister(gauge)
|
prometheus.MustRegister(gauge)
|
||||||
self.metric[key] = gauge
|
disk.metric[key] = gauge
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *DiskWidget) update() {
|
func (disk *DiskWidget) update() {
|
||||||
partitions, err := psDisk.Partitions(false)
|
partitions, err := psDisk.Partitions(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("failed to get disk partitions from gopsutil: %v", err)
|
log.Printf("failed to get disk partitions from gopsutil: %v", err)
|
||||||
|
@ -97,8 +97,8 @@ func (self *DiskWidget) update() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// check if partition doesn't already exist in our list
|
// check if partition doesn't already exist in our list
|
||||||
if _, ok := self.Partitions[partition.Device]; !ok {
|
if _, ok := disk.Partitions[partition.Device]; !ok {
|
||||||
self.Partitions[partition.Device] = &Partition{
|
disk.Partitions[partition.Device] = &Partition{
|
||||||
Device: partition.Device,
|
Device: partition.Device,
|
||||||
MountPoint: partition.Mountpoint,
|
MountPoint: partition.Mountpoint,
|
||||||
}
|
}
|
||||||
|
@ -107,7 +107,7 @@ func (self *DiskWidget) update() {
|
||||||
|
|
||||||
// delete a partition if it no longer exists
|
// delete a partition if it no longer exists
|
||||||
toDelete := []string{}
|
toDelete := []string{}
|
||||||
for device := range self.Partitions {
|
for device := range disk.Partitions {
|
||||||
exists := false
|
exists := false
|
||||||
for _, partition := range partitions {
|
for _, partition := range partitions {
|
||||||
if device == partition.Device {
|
if device == partition.Device {
|
||||||
|
@ -120,11 +120,11 @@ func (self *DiskWidget) update() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, device := range toDelete {
|
for _, device := range toDelete {
|
||||||
delete(self.Partitions, device)
|
delete(disk.Partitions, device)
|
||||||
}
|
}
|
||||||
|
|
||||||
// updates partition info. We add 0.5 to all values to make sure the truncation rounds
|
// updates partition info. We add 0.5 to all values to make sure the truncation rounds
|
||||||
for _, partition := range self.Partitions {
|
for _, partition := range disk.Partitions {
|
||||||
usage, err := psDisk.Usage(partition.MountPoint)
|
usage, err := psDisk.Usage(partition.MountPoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("failed to get partition usage statistics from gopsutil: %v. partition: %v", err, partition)
|
log.Printf("failed to get partition usage statistics from gopsutil: %v. partition: %v", err, partition)
|
||||||
|
@ -160,27 +160,27 @@ func (self *DiskWidget) update() {
|
||||||
// converts self.Partitions into self.Rows which is a [][]String
|
// converts self.Partitions into self.Rows which is a [][]String
|
||||||
|
|
||||||
sortedPartitions := []string{}
|
sortedPartitions := []string{}
|
||||||
for seriesName := range self.Partitions {
|
for seriesName := range disk.Partitions {
|
||||||
sortedPartitions = append(sortedPartitions, seriesName)
|
sortedPartitions = append(sortedPartitions, seriesName)
|
||||||
}
|
}
|
||||||
sort.Strings(sortedPartitions)
|
sort.Strings(sortedPartitions)
|
||||||
|
|
||||||
self.Rows = make([][]string, len(self.Partitions))
|
disk.Rows = make([][]string, len(disk.Partitions))
|
||||||
|
|
||||||
for i, key := range sortedPartitions {
|
for i, key := range sortedPartitions {
|
||||||
partition := self.Partitions[key]
|
partition := disk.Partitions[key]
|
||||||
self.Rows[i] = make([]string, 6)
|
disk.Rows[i] = make([]string, 6)
|
||||||
self.Rows[i][0] = strings.Replace(strings.Replace(partition.Device, "/dev/", "", -1), "mapper/", "", -1)
|
disk.Rows[i][0] = strings.Replace(strings.Replace(partition.Device, "/dev/", "", -1), "mapper/", "", -1)
|
||||||
self.Rows[i][1] = partition.MountPoint
|
disk.Rows[i][1] = partition.MountPoint
|
||||||
self.Rows[i][2] = fmt.Sprintf("%d%%", partition.UsedPercent)
|
disk.Rows[i][2] = fmt.Sprintf("%d%%", partition.UsedPercent)
|
||||||
self.Rows[i][3] = partition.Free
|
disk.Rows[i][3] = partition.Free
|
||||||
self.Rows[i][4] = partition.BytesReadRecently
|
disk.Rows[i][4] = partition.BytesReadRecently
|
||||||
self.Rows[i][5] = partition.BytesWrittenRecently
|
disk.Rows[i][5] = partition.BytesWrittenRecently
|
||||||
if self.metric != nil {
|
if disk.metric != nil {
|
||||||
if self.metric[key] == nil {
|
if disk.metric[key] == nil {
|
||||||
log.Printf("ERROR: missing metric %s", key)
|
log.Printf("ERROR: missing metric %s", key)
|
||||||
} else {
|
} else {
|
||||||
self.metric[key].Set(float64(partition.UsedPercent) / 100.0)
|
disk.metric[key].Set(float64(partition.UsedPercent) / 100.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
ui "github.com/gizak/termui/v3"
|
ui "github.com/gizak/termui/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// KEYBINDS is the help text for the in-program shortcuts
|
||||||
const KEYBINDS = `
|
const KEYBINDS = `
|
||||||
Quit: q or <C-c>
|
Quit: q or <C-c>
|
||||||
|
|
||||||
|
@ -55,7 +56,7 @@ func NewHelpMenu() *HelpMenu {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *HelpMenu) Resize(termWidth, termHeight int) {
|
func (help *HelpMenu) Resize(termWidth, termHeight int) {
|
||||||
textWidth := 53
|
textWidth := 53
|
||||||
for _, line := range strings.Split(KEYBINDS, "\n") {
|
for _, line := range strings.Split(KEYBINDS, "\n") {
|
||||||
if textWidth < len(line) {
|
if textWidth < len(line) {
|
||||||
|
@ -66,17 +67,17 @@ func (self *HelpMenu) Resize(termWidth, termHeight int) {
|
||||||
x := (termWidth - textWidth) / 2
|
x := (termWidth - textWidth) / 2
|
||||||
y := (termHeight - textHeight) / 2
|
y := (termHeight - textHeight) / 2
|
||||||
|
|
||||||
self.Block.SetRect(x, y, textWidth+x, textHeight+y)
|
help.Block.SetRect(x, y, textWidth+x, textHeight+y)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *HelpMenu) Draw(buf *ui.Buffer) {
|
func (help *HelpMenu) Draw(buf *ui.Buffer) {
|
||||||
self.Block.Draw(buf)
|
help.Block.Draw(buf)
|
||||||
|
|
||||||
for y, line := range strings.Split(KEYBINDS, "\n") {
|
for y, line := range strings.Split(KEYBINDS, "\n") {
|
||||||
for x, rune := range line {
|
for x, rune := range line {
|
||||||
buf.SetCell(
|
buf.SetCell(
|
||||||
ui.NewCell(rune, ui.Theme.Default),
|
ui.NewCell(rune, ui.Theme.Default),
|
||||||
image.Pt(self.Inner.Min.X+x, self.Inner.Min.Y+y-1),
|
image.Pt(help.Inner.Min.X+x, help.Inner.Min.Y+y-1),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,30 +48,30 @@ func NewMemWidget(updateInterval time.Duration, horizontalScale int) *MemWidget
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *MemWidget) EnableMetric() {
|
func (mem *MemWidget) EnableMetric() {
|
||||||
b.metrics = make(map[string]prometheus.Gauge)
|
mem.metrics = make(map[string]prometheus.Gauge)
|
||||||
mems := make(map[string]devices.MemoryInfo)
|
mems := make(map[string]devices.MemoryInfo)
|
||||||
devices.UpdateMem(mems)
|
devices.UpdateMem(mems)
|
||||||
for l, mem := range mems {
|
for l, m := range mems {
|
||||||
b.metrics[l] = prometheus.NewGauge(prometheus.GaugeOpts{
|
mem.metrics[l] = prometheus.NewGauge(prometheus.GaugeOpts{
|
||||||
Namespace: "gotop",
|
Namespace: "gotop",
|
||||||
Subsystem: "memory",
|
Subsystem: "memory",
|
||||||
Name: l,
|
Name: l,
|
||||||
})
|
})
|
||||||
b.metrics[l].Set(mem.UsedPercent)
|
mem.metrics[l].Set(m.UsedPercent)
|
||||||
prometheus.MustRegister(b.metrics[l])
|
prometheus.MustRegister(mem.metrics[l])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *MemWidget) Scale(i int) {
|
func (mem *MemWidget) Scale(i int) {
|
||||||
b.LineGraph.HorizontalScale = i
|
mem.LineGraph.HorizontalScale = i
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *MemWidget) renderMemInfo(line string, memoryInfo devices.MemoryInfo) {
|
func (mem *MemWidget) renderMemInfo(line string, memoryInfo devices.MemoryInfo) {
|
||||||
self.Data[line] = append(self.Data[line], memoryInfo.UsedPercent)
|
mem.Data[line] = append(mem.Data[line], memoryInfo.UsedPercent)
|
||||||
memoryTotalBytes, memoryTotalMagnitude := utils.ConvertBytes(memoryInfo.Total)
|
memoryTotalBytes, memoryTotalMagnitude := utils.ConvertBytes(memoryInfo.Total)
|
||||||
memoryUsedBytes, memoryUsedMagnitude := utils.ConvertBytes(memoryInfo.Used)
|
memoryUsedBytes, memoryUsedMagnitude := utils.ConvertBytes(memoryInfo.Used)
|
||||||
self.Labels[line] = fmt.Sprintf("%3.0f%% %5.1f%s/%.0f%s",
|
mem.Labels[line] = fmt.Sprintf("%3.0f%% %5.1f%s/%.0f%s",
|
||||||
memoryInfo.UsedPercent,
|
memoryInfo.UsedPercent,
|
||||||
memoryUsedBytes,
|
memoryUsedBytes,
|
||||||
memoryUsedMagnitude,
|
memoryUsedMagnitude,
|
||||||
|
|
|
@ -14,8 +14,10 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
NET_INTERFACE_ALL = "all"
|
// NetInterfaceAll enables all network interfaces
|
||||||
NET_INTERFACE_VPN = "tun0"
|
NetInterfaceAll = "all"
|
||||||
|
// NetInterfaceVpn is the VPN interface
|
||||||
|
NetInterfaceVpn = "tun0"
|
||||||
)
|
)
|
||||||
|
|
||||||
type NetWidget struct {
|
type NetWidget struct {
|
||||||
|
@ -63,23 +65,23 @@ func NewNetWidget(netInterface string) *NetWidget {
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *NetWidget) EnableMetric() {
|
func (net *NetWidget) EnableMetric() {
|
||||||
b.recvMetric = prometheus.NewCounter(prometheus.CounterOpts{
|
net.recvMetric = prometheus.NewCounter(prometheus.CounterOpts{
|
||||||
Namespace: "gotop",
|
Namespace: "gotop",
|
||||||
Subsystem: "net",
|
Subsystem: "net",
|
||||||
Name: "recv",
|
Name: "recv",
|
||||||
})
|
})
|
||||||
prometheus.MustRegister(b.recvMetric)
|
prometheus.MustRegister(net.recvMetric)
|
||||||
|
|
||||||
b.sentMetric = prometheus.NewCounter(prometheus.CounterOpts{
|
net.sentMetric = prometheus.NewCounter(prometheus.CounterOpts{
|
||||||
Namespace: "gotop",
|
Namespace: "gotop",
|
||||||
Subsystem: "net",
|
Subsystem: "net",
|
||||||
Name: "sent",
|
Name: "sent",
|
||||||
})
|
})
|
||||||
prometheus.MustRegister(b.sentMetric)
|
prometheus.MustRegister(net.sentMetric)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *NetWidget) update() {
|
func (net *NetWidget) update() {
|
||||||
interfaces, err := psNet.IOCounters(true)
|
interfaces, err := psNet.IOCounters(true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("failed to get network activity from gopsutil: %v", err)
|
log.Printf("failed to get network activity from gopsutil: %v", err)
|
||||||
|
@ -90,15 +92,15 @@ func (self *NetWidget) update() {
|
||||||
var totalBytesSent uint64
|
var totalBytesSent uint64
|
||||||
interfaceMap := make(map[string]bool)
|
interfaceMap := make(map[string]bool)
|
||||||
// Default behaviour
|
// Default behaviour
|
||||||
interfaceMap[NET_INTERFACE_ALL] = true
|
interfaceMap[NetInterfaceAll] = true
|
||||||
interfaceMap[NET_INTERFACE_VPN] = false
|
interfaceMap[NetInterfaceVpn] = false
|
||||||
// Build a map with wanted status for each interfaces.
|
// Build a map with wanted status for each interfaces.
|
||||||
for _, iface := range self.NetInterface {
|
for _, iface := range net.NetInterface {
|
||||||
if strings.HasPrefix(iface, "!") {
|
if strings.HasPrefix(iface, "!") {
|
||||||
interfaceMap[strings.TrimPrefix(iface, "!")] = false
|
interfaceMap[strings.TrimPrefix(iface, "!")] = false
|
||||||
} else {
|
} else {
|
||||||
// if we specify a wanted interface, remove capture on all.
|
// if we specify a wanted interface, remove capture on all.
|
||||||
delete(interfaceMap, NET_INTERFACE_ALL)
|
delete(interfaceMap, NetInterfaceAll)
|
||||||
interfaceMap[iface] = true
|
interfaceMap[iface] = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,7 +111,7 @@ func (self *NetWidget) update() {
|
||||||
totalBytesSent += _interface.BytesSent
|
totalBytesSent += _interface.BytesSent
|
||||||
} else if ok { // Present but unwanted
|
} else if ok { // Present but unwanted
|
||||||
continue
|
continue
|
||||||
} else if interfaceMap[NET_INTERFACE_ALL] { // Capture other
|
} else if interfaceMap[NetInterfaceAll] { // Capture other
|
||||||
totalBytesRecv += _interface.BytesRecv
|
totalBytesRecv += _interface.BytesRecv
|
||||||
totalBytesSent += _interface.BytesSent
|
totalBytesSent += _interface.BytesSent
|
||||||
}
|
}
|
||||||
|
@ -118,9 +120,9 @@ func (self *NetWidget) update() {
|
||||||
var recentBytesRecv uint64
|
var recentBytesRecv uint64
|
||||||
var recentBytesSent uint64
|
var recentBytesSent uint64
|
||||||
|
|
||||||
if self.totalBytesRecv != 0 { // if this isn't the first update
|
if net.totalBytesRecv != 0 { // if this isn't the first update
|
||||||
recentBytesRecv = totalBytesRecv - self.totalBytesRecv
|
recentBytesRecv = totalBytesRecv - net.totalBytesRecv
|
||||||
recentBytesSent = totalBytesSent - self.totalBytesSent
|
recentBytesSent = totalBytesSent - net.totalBytesSent
|
||||||
|
|
||||||
if int(recentBytesRecv) < 0 {
|
if int(recentBytesRecv) < 0 {
|
||||||
log.Printf("error: negative value for recently received network data from gopsutil. recentBytesRecv: %v", recentBytesRecv)
|
log.Printf("error: negative value for recently received network data from gopsutil. recentBytesRecv: %v", recentBytesRecv)
|
||||||
|
@ -133,20 +135,20 @@ func (self *NetWidget) update() {
|
||||||
recentBytesSent = 0
|
recentBytesSent = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
self.Lines[0].Data = append(self.Lines[0].Data, int(recentBytesRecv))
|
net.Lines[0].Data = append(net.Lines[0].Data, int(recentBytesRecv))
|
||||||
self.Lines[1].Data = append(self.Lines[1].Data, int(recentBytesSent))
|
net.Lines[1].Data = append(net.Lines[1].Data, int(recentBytesSent))
|
||||||
if self.sentMetric != nil {
|
if net.sentMetric != nil {
|
||||||
self.sentMetric.Add(float64(recentBytesSent))
|
net.sentMetric.Add(float64(recentBytesSent))
|
||||||
self.recvMetric.Add(float64(recentBytesRecv))
|
net.recvMetric.Add(float64(recentBytesRecv))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// used in later calls to update
|
// used in later calls to update
|
||||||
self.totalBytesRecv = totalBytesRecv
|
net.totalBytesRecv = totalBytesRecv
|
||||||
self.totalBytesSent = totalBytesSent
|
net.totalBytesSent = totalBytesSent
|
||||||
|
|
||||||
rx, tx := "RX/s", "TX/s"
|
rx, tx := "RX/s", "TX/s"
|
||||||
if self.Mbps {
|
if net.Mbps {
|
||||||
rx, tx = "mbps", "mbps"
|
rx, tx = "mbps", "mbps"
|
||||||
}
|
}
|
||||||
format := " %s: %9.1f %2s/s"
|
format := " %s: %9.1f %2s/s"
|
||||||
|
@ -163,13 +165,13 @@ func (self *NetWidget) update() {
|
||||||
}
|
}
|
||||||
|
|
||||||
totalConverted, unitTotal := utils.ConvertBytes(total)
|
totalConverted, unitTotal := utils.ConvertBytes(total)
|
||||||
if self.Mbps {
|
if net.Mbps {
|
||||||
recentConverted, unitRecent, format = float64(recent)*0.000008, "", " %s: %11.3f %2s"
|
recentConverted, unitRecent, format = float64(recent)*0.000008, "", " %s: %11.3f %2s"
|
||||||
} else {
|
} else {
|
||||||
recentConverted, unitRecent = utils.ConvertBytes(recent)
|
recentConverted, unitRecent = utils.ConvertBytes(recent)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.Lines[i].Title1 = fmt.Sprintf(" Total %s: %5.1f %s", label, totalConverted, unitTotal)
|
net.Lines[i].Title1 = fmt.Sprintf(" Total %s: %5.1f %s", label, totalConverted, unitTotal)
|
||||||
self.Lines[i].Title2 = fmt.Sprintf(format, rate, recentConverted, unitRecent)
|
net.Lines[i].Title2 = fmt.Sprintf(format, rate, recentConverted, unitRecent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
175
widgets/proc.go
175
widgets/proc.go
|
@ -17,14 +17,13 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
UP_ARROW = "▲"
|
_downArrow = "▼"
|
||||||
DOWN_ARROW = "▼"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type ProcSortMethod string
|
type ProcSortMethod string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ProcSortCpu ProcSortMethod = "c"
|
ProcSortCPU ProcSortMethod = "c"
|
||||||
ProcSortMem = "m"
|
ProcSortMem = "m"
|
||||||
ProcSortPid = "p"
|
ProcSortPid = "p"
|
||||||
)
|
)
|
||||||
|
@ -33,7 +32,7 @@ type Proc struct {
|
||||||
Pid int
|
Pid int
|
||||||
CommandName string
|
CommandName string
|
||||||
FullCommand string
|
FullCommand string
|
||||||
Cpu float64
|
CPU float64
|
||||||
Mem float64
|
Mem float64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +57,7 @@ func NewProcWidget() *ProcWidget {
|
||||||
Table: ui.NewTable(),
|
Table: ui.NewTable(),
|
||||||
updateInterval: time.Second,
|
updateInterval: time.Second,
|
||||||
cpuCount: cpuCount,
|
cpuCount: cpuCount,
|
||||||
sortMethod: ProcSortCpu,
|
sortMethod: ProcSortCPU,
|
||||||
showGroupedProcs: true,
|
showGroupedProcs: true,
|
||||||
filter: "",
|
filter: "",
|
||||||
}
|
}
|
||||||
|
@ -100,42 +99,42 @@ func NewProcWidget() *ProcWidget {
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ProcWidget) EnableMetric() {
|
func (proc *ProcWidget) EnableMetric() {
|
||||||
// There's (currently) no metric for this
|
// There's (currently) no metric for this
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ProcWidget) SetEditingFilter(editing bool) {
|
func (proc *ProcWidget) SetEditingFilter(editing bool) {
|
||||||
self.entry.SetEditing(editing)
|
proc.entry.SetEditing(editing)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ProcWidget) HandleEvent(e tui.Event) bool {
|
func (proc *ProcWidget) HandleEvent(e tui.Event) bool {
|
||||||
return self.entry.HandleEvent(e)
|
return proc.entry.HandleEvent(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ProcWidget) SetRect(x1, y1, x2, y2 int) {
|
func (proc *ProcWidget) SetRect(x1, y1, x2, y2 int) {
|
||||||
self.Table.SetRect(x1, y1, x2, y2)
|
proc.Table.SetRect(x1, y1, x2, y2)
|
||||||
self.entry.SetRect(x1+2, y2-1, x2-2, y2)
|
proc.entry.SetRect(x1+2, y2-1, x2-2, y2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ProcWidget) Draw(buf *tui.Buffer) {
|
func (proc *ProcWidget) Draw(buf *tui.Buffer) {
|
||||||
self.Table.Draw(buf)
|
proc.Table.Draw(buf)
|
||||||
self.entry.Draw(buf)
|
proc.entry.Draw(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ProcWidget) filterProcs(procs []Proc) []Proc {
|
func (proc *ProcWidget) filterProcs(procs []Proc) []Proc {
|
||||||
if self.filter == "" {
|
if proc.filter == "" {
|
||||||
return procs
|
return procs
|
||||||
}
|
}
|
||||||
var filtered []Proc
|
var filtered []Proc
|
||||||
for _, proc := range procs {
|
for _, p := range procs {
|
||||||
if strings.Contains(proc.FullCommand, self.filter) || strings.Contains(fmt.Sprintf("%d", proc.Pid), self.filter) {
|
if strings.Contains(p.FullCommand, proc.filter) || strings.Contains(fmt.Sprintf("%d", p.Pid), proc.filter) {
|
||||||
filtered = append(filtered, proc)
|
filtered = append(filtered, p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return filtered
|
return filtered
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ProcWidget) update() {
|
func (proc *ProcWidget) update() {
|
||||||
procs, err := getProcs()
|
procs, err := getProcs()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("failed to retrieve processes: %v", err)
|
log.Printf("failed to retrieve processes: %v", err)
|
||||||
|
@ -144,103 +143,103 @@ func (self *ProcWidget) update() {
|
||||||
|
|
||||||
// have to iterate over the entry number in order to modify the array in place
|
// have to iterate over the entry number in order to modify the array in place
|
||||||
for i := range procs {
|
for i := range procs {
|
||||||
procs[i].Cpu /= float64(self.cpuCount)
|
procs[i].CPU /= float64(proc.cpuCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
procs = self.filterProcs(procs)
|
procs = proc.filterProcs(procs)
|
||||||
self.ungroupedProcs = procs
|
proc.ungroupedProcs = procs
|
||||||
self.groupedProcs = groupProcs(procs)
|
proc.groupedProcs = groupProcs(procs)
|
||||||
|
|
||||||
self.sortProcs()
|
proc.sortProcs()
|
||||||
self.convertProcsToTableRows()
|
proc.convertProcsToTableRows()
|
||||||
}
|
}
|
||||||
|
|
||||||
// sortProcs sorts either the grouped or ungrouped []Process based on the sortMethod.
|
// sortProcs sorts either the grouped or ungrouped []Process based on the sortMethod.
|
||||||
// Called with every update, when the sort method is changed, and when processes are grouped and ungrouped.
|
// Called with every update, when the sort method is changed, and when processes are grouped and ungrouped.
|
||||||
func (self *ProcWidget) sortProcs() {
|
func (proc *ProcWidget) sortProcs() {
|
||||||
self.Header = []string{"Count", "Command", "CPU%", "Mem%"}
|
proc.Header = []string{"Count", "Command", "CPU%", "Mem%"}
|
||||||
|
|
||||||
if !self.showGroupedProcs {
|
if !proc.showGroupedProcs {
|
||||||
self.Header[0] = "PID"
|
proc.Header[0] = "PID"
|
||||||
}
|
}
|
||||||
|
|
||||||
var procs *[]Proc
|
var procs *[]Proc
|
||||||
if self.showGroupedProcs {
|
if proc.showGroupedProcs {
|
||||||
procs = &self.groupedProcs
|
procs = &proc.groupedProcs
|
||||||
} else {
|
} else {
|
||||||
procs = &self.ungroupedProcs
|
procs = &proc.ungroupedProcs
|
||||||
}
|
}
|
||||||
|
|
||||||
switch self.sortMethod {
|
switch proc.sortMethod {
|
||||||
case ProcSortCpu:
|
case ProcSortCPU:
|
||||||
sort.Sort(sort.Reverse(SortProcsByCpu(*procs)))
|
sort.Sort(sort.Reverse(SortProcsByCPU(*procs)))
|
||||||
self.Header[2] += DOWN_ARROW
|
proc.Header[2] += _downArrow
|
||||||
case ProcSortPid:
|
case ProcSortPid:
|
||||||
if self.showGroupedProcs {
|
if proc.showGroupedProcs {
|
||||||
sort.Sort(sort.Reverse(SortProcsByPid(*procs)))
|
sort.Sort(sort.Reverse(SortProcsByPid(*procs)))
|
||||||
} else {
|
} else {
|
||||||
sort.Sort(SortProcsByPid(*procs))
|
sort.Sort(SortProcsByPid(*procs))
|
||||||
}
|
}
|
||||||
self.Header[0] += DOWN_ARROW
|
proc.Header[0] += _downArrow
|
||||||
case ProcSortMem:
|
case ProcSortMem:
|
||||||
sort.Sort(sort.Reverse(SortProcsByMem(*procs)))
|
sort.Sort(sort.Reverse(SortProcsByMem(*procs)))
|
||||||
self.Header[3] += DOWN_ARROW
|
proc.Header[3] += _downArrow
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// convertProcsToTableRows converts a []Proc to a [][]string and sets it to the table Rows
|
// convertProcsToTableRows converts a []Proc to a [][]string and sets it to the table Rows
|
||||||
func (self *ProcWidget) convertProcsToTableRows() {
|
func (proc *ProcWidget) convertProcsToTableRows() {
|
||||||
var procs *[]Proc
|
var procs *[]Proc
|
||||||
if self.showGroupedProcs {
|
if proc.showGroupedProcs {
|
||||||
procs = &self.groupedProcs
|
procs = &proc.groupedProcs
|
||||||
} else {
|
} else {
|
||||||
procs = &self.ungroupedProcs
|
procs = &proc.ungroupedProcs
|
||||||
}
|
}
|
||||||
strings := make([][]string, len(*procs))
|
strings := make([][]string, len(*procs))
|
||||||
for i := range *procs {
|
for i := range *procs {
|
||||||
strings[i] = make([]string, 4)
|
strings[i] = make([]string, 4)
|
||||||
strings[i][0] = strconv.Itoa(int((*procs)[i].Pid))
|
strings[i][0] = strconv.Itoa(int((*procs)[i].Pid))
|
||||||
if self.showGroupedProcs {
|
if proc.showGroupedProcs {
|
||||||
strings[i][1] = (*procs)[i].CommandName
|
strings[i][1] = (*procs)[i].CommandName
|
||||||
} else {
|
} else {
|
||||||
strings[i][1] = (*procs)[i].FullCommand
|
strings[i][1] = (*procs)[i].FullCommand
|
||||||
}
|
}
|
||||||
strings[i][2] = fmt.Sprintf("%4s", strconv.FormatFloat((*procs)[i].Cpu, 'f', 1, 64))
|
strings[i][2] = fmt.Sprintf("%4s", strconv.FormatFloat((*procs)[i].CPU, 'f', 1, 64))
|
||||||
strings[i][3] = fmt.Sprintf("%4s", strconv.FormatFloat(float64((*procs)[i].Mem), 'f', 1, 64))
|
strings[i][3] = fmt.Sprintf("%4s", strconv.FormatFloat(float64((*procs)[i].Mem), 'f', 1, 64))
|
||||||
}
|
}
|
||||||
self.Rows = strings
|
proc.Rows = strings
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ProcWidget) ChangeProcSortMethod(method ProcSortMethod) {
|
func (proc *ProcWidget) ChangeProcSortMethod(method ProcSortMethod) {
|
||||||
if self.sortMethod != method {
|
if proc.sortMethod != method {
|
||||||
self.sortMethod = method
|
proc.sortMethod = method
|
||||||
self.ScrollTop()
|
proc.ScrollTop()
|
||||||
self.sortProcs()
|
proc.sortProcs()
|
||||||
self.convertProcsToTableRows()
|
proc.convertProcsToTableRows()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ProcWidget) ToggleShowingGroupedProcs() {
|
func (proc *ProcWidget) ToggleShowingGroupedProcs() {
|
||||||
self.showGroupedProcs = !self.showGroupedProcs
|
proc.showGroupedProcs = !proc.showGroupedProcs
|
||||||
if self.showGroupedProcs {
|
if proc.showGroupedProcs {
|
||||||
self.UniqueCol = 1
|
proc.UniqueCol = 1
|
||||||
} else {
|
} else {
|
||||||
self.UniqueCol = 0
|
proc.UniqueCol = 0
|
||||||
}
|
}
|
||||||
self.ScrollTop()
|
proc.ScrollTop()
|
||||||
self.sortProcs()
|
proc.sortProcs()
|
||||||
self.convertProcsToTableRows()
|
proc.convertProcsToTableRows()
|
||||||
}
|
}
|
||||||
|
|
||||||
// KillProc kills a process or group of processes depending on if we're
|
// KillProc kills a process or group of processes depending on if we're
|
||||||
// displaying the processes grouped or not.
|
// displaying the processes grouped or not.
|
||||||
func (self *ProcWidget) KillProc(sigName string) {
|
func (proc *ProcWidget) KillProc(sigName string) {
|
||||||
self.SelectedItem = ""
|
proc.SelectedItem = ""
|
||||||
command := "kill"
|
command := "kill"
|
||||||
if self.UniqueCol == 1 {
|
if proc.UniqueCol == 1 {
|
||||||
command = "pkill"
|
command = "pkill"
|
||||||
}
|
}
|
||||||
cmd := exec.Command(command, "--signal", sigName, self.Rows[self.SelectedRow][self.UniqueCol])
|
cmd := exec.Command(command, "--signal", sigName, proc.Rows[proc.SelectedRow][proc.UniqueCol])
|
||||||
cmd.Start()
|
cmd.Start()
|
||||||
cmd.Wait()
|
cmd.Wait()
|
||||||
}
|
}
|
||||||
|
@ -257,7 +256,7 @@ func groupProcs(procs []Proc) []Proc {
|
||||||
val.Pid + 1,
|
val.Pid + 1,
|
||||||
val.CommandName,
|
val.CommandName,
|
||||||
"",
|
"",
|
||||||
val.Cpu + proc.Cpu,
|
val.CPU + proc.CPU,
|
||||||
val.Mem + proc.Mem,
|
val.Mem + proc.Mem,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -265,7 +264,7 @@ func groupProcs(procs []Proc) []Proc {
|
||||||
1,
|
1,
|
||||||
proc.CommandName,
|
proc.CommandName,
|
||||||
"",
|
"",
|
||||||
proc.Cpu,
|
proc.CPU,
|
||||||
proc.Mem,
|
proc.Mem,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -283,53 +282,53 @@ func groupProcs(procs []Proc) []Proc {
|
||||||
|
|
||||||
// []Proc Sorting //////////////////////////////////////////////////////////////
|
// []Proc Sorting //////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
type SortProcsByCpu []Proc
|
type SortProcsByCPU []Proc
|
||||||
|
|
||||||
// Len implements Sort interface
|
// Len implements Sort interface
|
||||||
func (self SortProcsByCpu) Len() int {
|
func (procs SortProcsByCPU) Len() int {
|
||||||
return len(self)
|
return len(procs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Swap implements Sort interface
|
// Swap implements Sort interface
|
||||||
func (self SortProcsByCpu) Swap(i, j int) {
|
func (procs SortProcsByCPU) Swap(i, j int) {
|
||||||
self[i], self[j] = self[j], self[i]
|
procs[i], procs[j] = procs[j], procs[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Less implements Sort interface
|
// Less implements Sort interface
|
||||||
func (self SortProcsByCpu) Less(i, j int) bool {
|
func (procs SortProcsByCPU) Less(i, j int) bool {
|
||||||
return self[i].Cpu < self[j].Cpu
|
return procs[i].CPU < procs[j].CPU
|
||||||
}
|
}
|
||||||
|
|
||||||
type SortProcsByPid []Proc
|
type SortProcsByPid []Proc
|
||||||
|
|
||||||
// Len implements Sort interface
|
// Len implements Sort interface
|
||||||
func (self SortProcsByPid) Len() int {
|
func (procs SortProcsByPid) Len() int {
|
||||||
return len(self)
|
return len(procs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Swap implements Sort interface
|
// Swap implements Sort interface
|
||||||
func (self SortProcsByPid) Swap(i, j int) {
|
func (procs SortProcsByPid) Swap(i, j int) {
|
||||||
self[i], self[j] = self[j], self[i]
|
procs[i], procs[j] = procs[j], procs[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Less implements Sort interface
|
// Less implements Sort interface
|
||||||
func (self SortProcsByPid) Less(i, j int) bool {
|
func (procs SortProcsByPid) Less(i, j int) bool {
|
||||||
return self[i].Pid < self[j].Pid
|
return procs[i].Pid < procs[j].Pid
|
||||||
}
|
}
|
||||||
|
|
||||||
type SortProcsByMem []Proc
|
type SortProcsByMem []Proc
|
||||||
|
|
||||||
// Len implements Sort interface
|
// Len implements Sort interface
|
||||||
func (self SortProcsByMem) Len() int {
|
func (procs SortProcsByMem) Len() int {
|
||||||
return len(self)
|
return len(procs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Swap implements Sort interface
|
// Swap implements Sort interface
|
||||||
func (self SortProcsByMem) Swap(i, j int) {
|
func (procs SortProcsByMem) Swap(i, j int) {
|
||||||
self[i], self[j] = self[j], self[i]
|
procs[i], procs[j] = procs[j], procs[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Less implements Sort interface
|
// Less implements Sort interface
|
||||||
func (self SortProcsByMem) Less(i, j int) bool {
|
func (procs SortProcsByMem) Less(i, j int) bool {
|
||||||
return self[i].Mem < self[j].Mem
|
return procs[i].Mem < procs[j].Mem
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ func getProcs() ([]Proc, error) {
|
||||||
Pid: pid,
|
Pid: pid,
|
||||||
CommandName: strings.TrimSpace(line[11:61]),
|
CommandName: strings.TrimSpace(line[11:61]),
|
||||||
FullCommand: line[74:],
|
FullCommand: line[74:],
|
||||||
Cpu: cpu,
|
CPU: cpu,
|
||||||
Mem: mem,
|
Mem: mem,
|
||||||
}
|
}
|
||||||
procs = append(procs, proc)
|
procs = append(procs, proc)
|
||||||
|
|
|
@ -19,8 +19,8 @@ func NewStatusBar() *StatusBar {
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StatusBar) Draw(buf *ui.Buffer) {
|
func (sb *StatusBar) Draw(buf *ui.Buffer) {
|
||||||
self.Block.Draw(buf)
|
sb.Block.Draw(buf)
|
||||||
|
|
||||||
hostname, err := os.Hostname()
|
hostname, err := os.Hostname()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -30,7 +30,7 @@ func (self *StatusBar) Draw(buf *ui.Buffer) {
|
||||||
buf.SetString(
|
buf.SetString(
|
||||||
hostname,
|
hostname,
|
||||||
ui.Theme.Default,
|
ui.Theme.Default,
|
||||||
image.Pt(self.Inner.Min.X, self.Inner.Min.Y+(self.Inner.Dy()/2)),
|
image.Pt(sb.Inner.Min.X, sb.Inner.Min.Y+(sb.Inner.Dy()/2)),
|
||||||
)
|
)
|
||||||
|
|
||||||
currentTime := time.Now()
|
currentTime := time.Now()
|
||||||
|
@ -39,8 +39,8 @@ func (self *StatusBar) Draw(buf *ui.Buffer) {
|
||||||
formattedTime,
|
formattedTime,
|
||||||
ui.Theme.Default,
|
ui.Theme.Default,
|
||||||
image.Pt(
|
image.Pt(
|
||||||
self.Inner.Min.X+(self.Inner.Dx()/2)-len(formattedTime)/2,
|
sb.Inner.Min.X+(sb.Inner.Dx()/2)-len(formattedTime)/2,
|
||||||
self.Inner.Min.Y+(self.Inner.Dy()/2),
|
sb.Inner.Min.Y+(sb.Inner.Dy()/2),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -48,8 +48,8 @@ func (self *StatusBar) Draw(buf *ui.Buffer) {
|
||||||
"gotop",
|
"gotop",
|
||||||
ui.Theme.Default,
|
ui.Theme.Default,
|
||||||
image.Pt(
|
image.Pt(
|
||||||
self.Inner.Max.X-6,
|
sb.Inner.Max.X-6,
|
||||||
self.Inner.Min.Y+(self.Inner.Dy()/2),
|
sb.Inner.Min.Y+(sb.Inner.Dy()/2),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,9 +68,9 @@ func NewTempWidget(tempScale TempScale, filter []string) *TempWidget {
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *TempWidget) EnableMetric() {
|
func (temp *TempWidget) EnableMetric() {
|
||||||
self.tempsMetric = make(map[string]prometheus.Gauge)
|
temp.tempsMetric = make(map[string]prometheus.Gauge)
|
||||||
for k, v := range self.Data {
|
for k, v := range temp.Data {
|
||||||
gauge := prometheus.NewGauge(prometheus.GaugeOpts{
|
gauge := prometheus.NewGauge(prometheus.GaugeOpts{
|
||||||
Namespace: "gotop",
|
Namespace: "gotop",
|
||||||
Subsystem: "temp",
|
Subsystem: "temp",
|
||||||
|
@ -78,58 +78,58 @@ func (self *TempWidget) EnableMetric() {
|
||||||
})
|
})
|
||||||
gauge.Set(float64(v))
|
gauge.Set(float64(v))
|
||||||
prometheus.MustRegister(gauge)
|
prometheus.MustRegister(gauge)
|
||||||
self.tempsMetric[k] = gauge
|
temp.tempsMetric[k] = gauge
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Custom Draw method instead of inheriting from a generic Widget.
|
// Custom Draw method instead of inheriting from a generic Widget.
|
||||||
func (self *TempWidget) Draw(buf *ui.Buffer) {
|
func (temp *TempWidget) Draw(buf *ui.Buffer) {
|
||||||
self.Block.Draw(buf)
|
temp.Block.Draw(buf)
|
||||||
|
|
||||||
var keys []string
|
var keys []string
|
||||||
for key := range self.Data {
|
for key := range temp.Data {
|
||||||
keys = append(keys, key)
|
keys = append(keys, key)
|
||||||
}
|
}
|
||||||
sort.Strings(keys)
|
sort.Strings(keys)
|
||||||
|
|
||||||
for y, key := range keys {
|
for y, key := range keys {
|
||||||
if y+1 > self.Inner.Dy() {
|
if y+1 > temp.Inner.Dy() {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
var fg ui.Color
|
var fg ui.Color
|
||||||
if self.Data[key] < self.TempThreshold {
|
if temp.Data[key] < temp.TempThreshold {
|
||||||
fg = self.TempLowColor
|
fg = temp.TempLowColor
|
||||||
} else {
|
} else {
|
||||||
fg = self.TempHighColor
|
fg = temp.TempHighColor
|
||||||
}
|
}
|
||||||
|
|
||||||
s := ui.TrimString(key, (self.Inner.Dx() - 4))
|
s := ui.TrimString(key, (temp.Inner.Dx() - 4))
|
||||||
buf.SetString(s,
|
buf.SetString(s,
|
||||||
ui.Theme.Default,
|
ui.Theme.Default,
|
||||||
image.Pt(self.Inner.Min.X, self.Inner.Min.Y+y),
|
image.Pt(temp.Inner.Min.X, temp.Inner.Min.Y+y),
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.tempsMetric != nil {
|
if temp.tempsMetric != nil {
|
||||||
self.tempsMetric[key].Set(float64(self.Data[key]))
|
temp.tempsMetric[key].Set(float64(temp.Data[key]))
|
||||||
}
|
}
|
||||||
temperature := fmt.Sprintf("%3d°%c", self.Data[key], self.TempScale)
|
temperature := fmt.Sprintf("%3d°%c", temp.Data[key], temp.TempScale)
|
||||||
|
|
||||||
buf.SetString(
|
buf.SetString(
|
||||||
temperature,
|
temperature,
|
||||||
ui.NewStyle(fg),
|
ui.NewStyle(fg),
|
||||||
image.Pt(self.Inner.Max.X-(len(temperature)-1), self.Inner.Min.Y+y),
|
image.Pt(temp.Inner.Max.X-(len(temperature)-1), temp.Inner.Min.Y+y),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *TempWidget) update() {
|
func (temp *TempWidget) update() {
|
||||||
devices.UpdateTemps(self.Data)
|
devices.UpdateTemps(temp.Data)
|
||||||
for name, val := range self.Data {
|
for name, val := range temp.Data {
|
||||||
if self.TempScale == Fahrenheit {
|
if temp.TempScale == Fahrenheit {
|
||||||
self.Data[name] = utils.CelsiusToFahrenheit(val)
|
temp.Data[name] = utils.CelsiusToFahrenheit(val)
|
||||||
} else {
|
} else {
|
||||||
self.Data[name] = val
|
temp.Data[name] = val
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user