Redundant Mem prefix
[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         "time"
13 )
14
15 var (
16         MyPID string = strconv.Itoa(os.Getpid())
17         CPU   string = "?"
18         Mem   string = "?"
19         ARC   string = "?"
20         Swap  string = "?"
21         Flags string = "?"
22         IOs   string = "?"
23         Net   string = "?"
24         N     string = "?"
25 )
26
27 func piper(c chan []string, name string, args ...string) error {
28         cmd := exec.Command(name, args...)
29         r, err := cmd.StdoutPipe()
30         if err != nil {
31                 return err
32         }
33         err = cmd.Start()
34         if err != nil {
35                 return err
36         }
37         scanner := bufio.NewScanner(r)
38         for scanner.Scan() {
39                 cols := strings.Fields(scanner.Text())
40                 if len(cols) > 0 {
41                         c <- cols
42                 }
43         }
44         if err = scanner.Err(); err != nil {
45                 cmd.Process.Kill()
46                 cmd.Wait()
47                 return err
48         }
49         return nil
50 }
51
52 func bg(cmd string, args ...string) chan []string {
53         c := make(chan []string)
54         go func() {
55                 for {
56                         err := piper(c, cmd, args...)
57                         if err != nil {
58                                 log.Println("error:", cmd, ":", err)
59                         }
60                         time.Sleep(time.Second)
61                 }
62         }()
63         return c
64 }
65
66 func top() {
67         for cols := range bg("top", "-b", "-d", "infinity", "-p", MyPID, "-s", "5", "infinity") {
68                 switch cols[0] {
69                 case "CPU:":
70                         CPU = strings.ReplaceAll(
71                                 strings.Join([]string{cols[1], cols[5], cols[7]}, " "),
72                                 "%", "",
73                         )
74                 case "Mem:":
75                         Mem = strings.ReplaceAll(strings.Join(cols[1:], " "), ",", "")
76                 case "ARC:":
77                         ARC = cols[1]
78                 case "Swap:":
79                         if cols[4] == "Used," {
80                                 Swap = cols[3] + " Swap "
81                         } else {
82                                 Swap = ""
83                         }
84                 }
85         }
86 }
87
88 func iostat(devs ...string) {
89         stats := make([]string, len(devs)*4)
90         for i := 0; i < len(devs); i++ {
91                 stats[i*4+1] = "/"
92                 stats[i*4+3] = " "
93         }
94         stats = stats[:len(stats)-1]
95         for cols := range bg("iostat", append([]string{"-d", "-w", N, "-x"}, devs...)...) {
96                 for i, dev := range devs {
97                         if cols[0] == dev {
98                                 stats[i*4+0] = cols[1]
99                                 stats[i*4+2] = cols[2]
100                                 IOs = strings.Join(stats, "")
101                         }
102                 }
103         }
104 }
105
106 func netstat() {
107         stats := []string{"0", "0"}
108         for cols := range bg("netstat", "-n", N) {
109                 if _, err := strconv.Atoi(cols[0]); err == nil {
110                         stats[0] = cols[0]
111                         stats[1] = cols[4]
112                         Net = strings.Join(stats, "/")
113                 }
114         }
115 }
116
117 func flagfiles() {
118         ents, err := os.ReadDir("/tmp/stargrave-flags")
119         if err != nil {
120                 log.Println(err)
121                 return
122         }
123         fs := make([]string, 0, len(ents))
124         for _, ent := range ents {
125                 fs = append(fs, ent.Name())
126         }
127         Flags = strings.Join(fs, " ")
128 }
129
130 func main() {
131         xsetroot := flag.Bool("xsetroot", false, "Call xsetroot")
132         iodevs := flag.String("iodevs", "ada0 ada1", "iostat devices")
133         refresh := flag.Uint("refresh", 2, "Refresh interval")
134         flag.Parse()
135         N = strconv.Itoa(int(*refresh))
136         go func() {
137                 for {
138                         flagfiles()
139                         time.Sleep(20 * time.Second)
140                 }
141         }()
142         go top()
143         go iostat(strings.Split(*iodevs, " ")...)
144         go netstat()
145         var now time.Time
146         var status string
147         var cmd *exec.Cmd
148         for {
149                 now = time.Now()
150                 status = fmt.Sprintf(
151                         "[IO %s]  [Net %s]  [CPU %s]  [%s%s %s ARC]  [%s] %s",
152                         IOs, Net, CPU, Swap, Mem, ARC, Flags,
153                         now.Format("2006-01-02 15:04:05"),
154                 )
155                 if *xsetroot {
156                         cmd = exec.Command("xsetroot", "-name", status)
157                         cmd.Run()
158                 } else {
159                         fmt.Println(status)
160                 }
161                 time.Sleep(time.Duration(*refresh) * time.Second)
162         }
163 }