package proc import ( "bufio" "finally-a-monolithic-linux-hw-monitor/app/proc/drivers" "fmt" "os" "strings" ) func RenderProc(console *strings.Builder, proc *Proc) { fmt.Fprintf(console, "=== %s ===\n", proc.Model()) RenderTemperatureSensors(console, proc) RenderPowerSensors(console, proc) RenderClockSensors(console, proc) } func RenderTemperatureSensors(console *strings.Builder, proc *Proc) { temps, _ := proc.SensorReader.ReadTemperatureSensors() fmt.Fprint(console, "--- Temperature ---\n") for _, sensor := range temps { tempC := sensor.TempC tempF := (tempC * 9 / 5) + 32 // \033[K clears from cursor to end of line (prevents lingering chars) fmt.Fprintf(console, "%-16s | %.2f °C (%.3f °F)\033[K\n", sensor.Name, tempC, tempF) } } func RenderPowerSensors(console *strings.Builder, proc *Proc) { fmt.Fprint(console, "--- Power ---\n") power, _ := proc.SensorReader.ReadPowerSensors() for _, sensor := range power { // \033[K clears from cursor to end of line (prevents lingering chars) fmt.Fprintf(console, "%-16s | %.2f W\033[K\n", sensor.Name, sensor.Watts) } } func RenderClockSensors(console *strings.Builder, proc *Proc) { fmt.Fprint(console, "--- Clock Frequency ---\n") power, _ := proc.SensorReader.ReadClockSensors() for _, sensor := range power { // \033[K clears from cursor to end of line (prevents lingering chars) fmt.Fprintf(console, "%-16s | %.2f GHz\033[K\n", sensor.Name, sensor.FrequencyGHz) } } type Proc struct { SensorReader ProcSensorReader Info map[string]string } type ProcSensorReader interface { ReadTemperatureSensors() ([]drivers.TemperatureSensor, error) ReadPowerSensors() ([]drivers.PowerSensor, error) ReadClockSensors() ([]drivers.ClockSensor, error) } const ( VendorIntel string = "GenuineIntel" VendorAMD string = "AuthenticAMD" VendorUnknown string = "Unknown" ) func GetProc() (Proc, error) { // open and parse cpuinfo proc := Proc{} procFile, err := os.Open("/proc/cpuinfo") if err != nil { return proc, err } defer procFile.Close() proc.Info = map[string]string{} scanner := bufio.NewScanner(procFile) if scanner.Err() != nil { return proc, scanner.Err() } for scanner.Scan() { line := scanner.Text() line = strings.ReplaceAll(line, "\t", "") if line != "" { x := strings.Split(line, ": ") if len(x) != 2 { continue } key := x[0] value := x[1] proc.Info[key] = value } } vendor := proc.Vendor() switch vendor { case VendorIntel: intelReader, err := NewIntelReader() proc.SensorReader = intelReader return proc, err case VendorAMD: amdReader, err := NewAMDReader() proc.SensorReader = amdReader return proc, err default: return proc, fmt.Errorf("proc type %s is not supported", vendor) } } func (proc *Proc) Vendor() string { return proc.Info["vendor_id"] } func (proc *Proc) Model() string { return proc.Info["model name"] }