initial commit with AI Code
This commit is contained in:
82
cmd/monitor/main.go
Normal file
82
cmd/monitor/main.go
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/shirou/gopsutil/v3/cpu"
|
||||||
|
"github.com/shirou/gopsutil/v3/mem"
|
||||||
|
)
|
||||||
|
|
||||||
|
func isSupported() bool {
|
||||||
|
goos := os.Getenv("TMUX_SYSUSAGE_GOOS") // Debug/Override optional
|
||||||
|
if goos == "" {
|
||||||
|
goos = detectGOOS()
|
||||||
|
}
|
||||||
|
switch goos {
|
||||||
|
case "darwin":
|
||||||
|
return true
|
||||||
|
case "linux":
|
||||||
|
id := linuxID()
|
||||||
|
return id == "ubuntu" || id == "arch"
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func detectGOOS() string {
|
||||||
|
// runtime.GOOS vermeiden, um Import minimal zu halten? Es ist Standard—nutzen wir.
|
||||||
|
// (Minimale Imports sind nice-to-have, aber runtime ist winzig.)
|
||||||
|
// Wir nehmen ihn doch, weil zuverlässig.
|
||||||
|
// → Ein einzelner Import mehr ist ok.
|
||||||
|
return runtimeGOOS()
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:noinline
|
||||||
|
func runtimeGOOS() string {
|
||||||
|
// kleiner Trick: getrennt, damit der Compiler runtime nicht inlined—irrelevant, aber clean.
|
||||||
|
return getGOOS()
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname getGOOS runtime.GOOS
|
||||||
|
func getGOOS() string
|
||||||
|
|
||||||
|
func linuxID() string {
|
||||||
|
f, err := os.Open("/etc/os-release")
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
sc := bufio.NewScanner(f)
|
||||||
|
for sc.Scan() {
|
||||||
|
line := sc.Text()
|
||||||
|
if strings.HasPrefix(line, "ID=") {
|
||||||
|
val := strings.TrimPrefix(line, "ID=")
|
||||||
|
val = strings.Trim(val, `"`)
|
||||||
|
return strings.ToLower(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if !isSupported() {
|
||||||
|
// Keine Ausgabe auf nicht unterstützten Systemen
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Kurze CPU-Stichprobe
|
||||||
|
values, err := cpu.Percent(400*time.Millisecond, false)
|
||||||
|
if err != nil || len(values) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
vm, err := mem.VirtualMemory()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Kompakte tmux-Ausgabe
|
||||||
|
fmt.Printf("CPU %.0f%% | RAM %.0f%%", values[0], vm.UsedPercent)
|
||||||
|
}
|
||||||
|
|
||||||
16
go.mod
Normal file
16
go.mod
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
module gitea.mschirmer.com/m13r/cpu-mem-monitor
|
||||||
|
|
||||||
|
go 1.25.1
|
||||||
|
|
||||||
|
require github.com/shirou/gopsutil/v3 v3.24.5
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||||
|
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
||||||
|
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
|
||||||
|
github.com/shoenig/go-m1cpu v0.1.6 // indirect
|
||||||
|
github.com/tklauser/go-sysconf v0.3.12 // indirect
|
||||||
|
github.com/tklauser/numcpus v0.6.1 // indirect
|
||||||
|
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||||
|
golang.org/x/sys v0.20.0 // indirect
|
||||||
|
)
|
||||||
36
go.sum
Normal file
36
go.sum
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||||
|
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||||
|
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
|
||||||
|
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
|
||||||
|
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||||
|
github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI=
|
||||||
|
github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk=
|
||||||
|
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
|
||||||
|
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
|
||||||
|
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
|
||||||
|
github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
|
||||||
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
|
||||||
|
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
|
||||||
|
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
|
||||||
|
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
|
||||||
|
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||||
|
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||||
|
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||||
|
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
111
main.go
Normal file
111
main.go
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
// cmd/sysusage/main.go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/shirou/gopsutil/v3/cpu"
|
||||||
|
"github.com/shirou/gopsutil/v3/mem"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Result struct {
|
||||||
|
CPUPercent float64 `json:"cpu_percent"`
|
||||||
|
RAMPercent float64 `json:"ram_percent"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func sampleCPU(interval time.Duration, samples int) (float64, error) {
|
||||||
|
if samples <= 0 {
|
||||||
|
samples = 1
|
||||||
|
}
|
||||||
|
var sum float64
|
||||||
|
for i := 0; i < samples; i++ {
|
||||||
|
// cpu.Percent blockiert für "interval" und liefert die Auslastung in diesem Zeitfenster
|
||||||
|
values, err := cpu.Percent(interval, false)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if len(values) == 0 {
|
||||||
|
return 0, fmt.Errorf("no cpu values returned")
|
||||||
|
}
|
||||||
|
sum += values[0]
|
||||||
|
}
|
||||||
|
return sum / float64(samples), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readRAM() (float64, error) {
|
||||||
|
vm, err := mem.VirtualMemory()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return vm.UsedPercent, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var (
|
||||||
|
intervalStr string
|
||||||
|
samples int
|
||||||
|
jsonOut bool
|
||||||
|
watch bool
|
||||||
|
)
|
||||||
|
|
||||||
|
flag.StringVar(&intervalStr, "interval", "1s", "Messintervall pro Stichprobe (z.B. 200ms, 1s, 2s)")
|
||||||
|
flag.IntVar(&samples, "samples", 1, "Anzahl der Stichproben (über das Intervall gemittelt)")
|
||||||
|
flag.BoolVar(&jsonOut, "json", false, "Ausgabe als JSON")
|
||||||
|
flag.BoolVar(&watch, "watch", false, "Kontinuierlich messen, bis Strg+C")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
interval, err := time.ParseDuration(intervalStr)
|
||||||
|
if err != nil || interval <= 0 {
|
||||||
|
log.Fatalf("ungültiges -interval: %v", intervalStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
printOnce := func() error {
|
||||||
|
cpuPct, err := sampleCPU(interval, samples)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("CPU-Messung fehlgeschlagen: %w", err)
|
||||||
|
}
|
||||||
|
ramPct, err := readRAM()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("RAM-Messung fehlgeschlagen: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if jsonOut {
|
||||||
|
out := Result{CPUPercent: cpuPct, RAMPercent: ramPct}
|
||||||
|
enc := json.NewEncoder(stdoutNoHTMLEscape{})
|
||||||
|
enc.SetIndent("", " ")
|
||||||
|
return enc.Encode(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("CPU: %.1f%% | RAM: %.1f%%\n", cpuPct, ramPct)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if watch {
|
||||||
|
for {
|
||||||
|
if err := printOnce(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
// Bei watch: zwischen den Zeilen kurz pausieren, damit die Ausgabe lesbar bleibt.
|
||||||
|
time.Sleep(250 * time.Millisecond)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := printOnce(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// stdoutNoHTMLEscape verhindert das HTML-Escaping des Standard-Encoders (nur Kosmetik für JSON)
|
||||||
|
type stdoutNoHTMLEscape struct{}
|
||||||
|
|
||||||
|
func (stdoutNoHTMLEscape) Write(p []byte) (int, error) { return fmt.Print(string(p)) }
|
||||||
|
func (stdoutNoHTMLEscape) Encode(v any) error {
|
||||||
|
enc := json.NewEncoder(stdoutNoHTMLEscape{})
|
||||||
|
enc.SetEscapeHTML(false)
|
||||||
|
return enc.Encode(v)
|
||||||
|
}
|
||||||
|
|
||||||
12
plugin.tmux
Normal file
12
plugin.tmux
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# Binary bauen (still). Wenn go fehlt: überspringen
|
||||||
|
run-shell "cd '#{plugin_path}' && GO111MODULE=on go mod tidy >/dev/null 2>&1 || true"
|
||||||
|
run-shell "cd '#{plugin_path}' && GO111MODULE=on go build -ldflags='-s -w' -o bin.sysusage ./cmd/monitor >/dev/null 2>&1 || true"
|
||||||
|
|
||||||
|
# tmux-Variable setzen: #{sysusage}
|
||||||
|
set -g @sysusage_cmd '#{plugin_path}/bin.sysusage'
|
||||||
|
set -g status-interval 2
|
||||||
|
|
||||||
|
# Du kannst später im Theme einfach schreiben:
|
||||||
|
# set -g status-right "... #{sysusage} ..."
|
||||||
|
set -g -F @sysusage '#(@sysusage_cmd)'
|
||||||
|
|
||||||
Reference in New Issue
Block a user