]> Sergey Matveev's repositories - godwmstat.git/blob - main.go
Shorter NIC names
[godwmstat.git] / main.go
1 package main
2
3 import (
4         "bufio"
5         "flag"
6         "fmt"
7         "log"
8         "os"
9         "os/exec"
10         "strconv"
11         "strings"
12         "sync"
13         "time"
14
15         "github.com/dustin/go-humanize"
16 )
17
18 var (
19         MyPID string = strconv.Itoa(os.Getpid())
20         CPU   string = "?"
21         Freq  string = "?"
22         Mem   string = "?"
23         ARC   string = "?"
24         Swap  string = ""
25         Flags string = "?"
26         IOs   string = "?"
27         Net          = map[string]string{}
28         NetM  sync.RWMutex
29 )
30
31 func piper(c chan []string, name string, args ...string) error {
32         cmd := exec.Command(name, args...)
33         r, err := cmd.StdoutPipe()
34         if err != nil {
35                 return err
36         }
37         err = cmd.Start()
38         if err != nil {
39                 return err
40         }
41         scanner := bufio.NewScanner(r)
42         for scanner.Scan() {
43                 cols := strings.Fields(scanner.Text())
44                 if len(cols) > 0 {
45                         c <- cols
46                 }
47         }
48         cmd.Process.Kill()
49         cmd.Wait()
50         return scanner.Err()
51 }
52
53 func bg(cmd string, args ...string) chan []string {
54         c := make(chan []string)
55         go func() {
56                 for {
57                         err := piper(c, cmd, args...)
58                         if err != nil {
59                                 log.Println("error:", cmd, ":", err)
60                         }
61                         time.Sleep(time.Second)
62                 }
63         }()
64         return c
65 }
66
67 func top() {
68         for cols := range bg("top", "-b", "-d", "infinity", "-p", MyPID, "-s", "5", "infinity") {
69                 switch cols[0] {
70                 case "CPU:":
71                         CPU = strings.ReplaceAll(fmt.Sprintf(
72                                 "%s sys:%s int:%s n:%s",
73                                 cols[1], cols[5], cols[7], cols[3],
74                         ), "%", "")
75                 case "Mem:":
76                         Mem = strings.ReplaceAll(strings.Join(cols[1:], " "), ",", "")
77                 case "ARC:":
78                         ARC = cols[1]
79                 case "Swap:":
80                         if len(cols) >= 5 && cols[4] == "Used," {
81                                 Swap = cols[3] + " Swap "
82                         }
83                 }
84         }
85 }
86
87 func iostat() {
88         var stats []string
89         for cols := range bg("iostat", "-d", "-w", "1", "-x") {
90                 if cols[0] == "device" {
91                         IOs = strings.Join(stats, " ")
92                         stats = nil
93                         continue
94                 }
95                 if len(cols) < 4 || (cols[1] == "0" && cols[2] == "0") {
96                         continue
97                 }
98                 stats = append(stats, fmt.Sprintf("%s:%s/%s", cols[0], cols[1], cols[2]))
99         }
100 }
101
102 func netstat(iface, short string) {
103         for cols := range bg("netstat", "-I", iface, "-n", "1") {
104                 if _, err := strconv.Atoi(cols[0]); err != nil {
105                         continue
106                 }
107                 ibps, err := strconv.Atoi(cols[3])
108                 if err != nil {
109                         continue
110                 }
111                 obps, err := strconv.Atoi(cols[6])
112                 if err != nil {
113                         continue
114                 }
115                 _ = cols[0] // pkts rx
116                 _ = cols[4] // pkts tx
117                 NetM.Lock()
118                 Net[short] = fmt.Sprintf(
119                         "%s:%s/%s",
120                         short,
121                         humanize.IBytes(uint64(ibps)),
122                         humanize.IBytes(uint64(obps)),
123                 )
124                 NetM.Unlock()
125         }
126 }
127
128 func freq() {
129         for cols := range bg("sysctl", "-n", "dev.cpu.0.freq") {
130                 if strings.HasSuffix(cols[0], "01") {
131                         Freq = "TB"
132                 } else {
133                         raw, err := strconv.Atoi(cols[0])
134                         if err != nil {
135                                 continue
136                         }
137                         Freq = fmt.Sprintf("%.1fG", float64(raw)/1000)
138                 }
139         }
140 }
141
142 func flagfiles() {
143         ents, err := os.ReadDir("/tmp/stargrave-flags")
144         if err != nil {
145                 log.Println(err)
146                 return
147         }
148         fs := make([]string, 0, len(ents))
149         for _, ent := range ents {
150                 fs = append(fs, ent.Name())
151         }
152         Flags = strings.Join(fs, " ")
153 }
154
155 func main() {
156         xsetroot := flag.Bool("xsetroot", false, "Call xsetroot")
157         flag.Parse()
158         go func() {
159                 for {
160                         flagfiles()
161                         time.Sleep(20 * time.Second)
162                 }
163         }()
164         go top()
165         go freq()
166         go iostat()
167         go netstat("bridge0", "br")
168         go netstat("ix0", "ix")
169         var now time.Time
170         var status string
171         var cmd *exec.Cmd
172         for {
173                 now = time.Now()
174                 NetM.RLock()
175                 status = fmt.Sprintf(
176                         "[%s]  [%s %s]  [%s %s]  [%s%s %s ARC]  [%s] %s",
177                         IOs, Net["br"], Net["ix"], CPU, Freq, Swap, Mem, ARC, Flags,
178                         now.Format("2006-01-02 15:04:05"),
179                 )
180                 NetM.RUnlock()
181                 if *xsetroot {
182                         cmd = exec.Command("xsetroot", "-name", status)
183                         cmd.Run()
184                 } else {
185                         fmt.Println(status)
186                 }
187                 time.Sleep(time.Second)
188         }
189 }