From 4cbddac5126375b85e80742b999013a4a7eb870b Mon Sep 17 00:00:00 2001 From: shirou Date: Sat, 24 Feb 2024 04:03:24 +0000 Subject: [PATCH] [sensors][linux]: add ExLinux on sensors. This commit references and fixes #1589. Thank you! --- sensors/ex_linux.go | 79 ++++++++++++++++++++++++++++++++++++++++ sensors/sensors_linux.go | 54 ++++++++++++++++----------- 2 files changed, 111 insertions(+), 22 deletions(-) create mode 100644 sensors/ex_linux.go diff --git a/sensors/ex_linux.go b/sensors/ex_linux.go new file mode 100644 index 000000000..081d64f36 --- /dev/null +++ b/sensors/ex_linux.go @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: BSD-3-Clause +//go:build linux + +package sensors + +import ( + "context" + "fmt" + "os" + "path/filepath" + "strings" +) + +// ExTemperature represents Linux dependent temperature sensor data +type ExTemperature struct { + SensorKey string `json:"key"` + Min float64 `json:"min"` // Temperature min value. + Lowest float64 `json:"lowest"` // Historical minimum temperature + Highest float64 `json:"highest"` // Historical maximum temperature +} + +type ExLinux struct{} + +func NewExLinux() *ExLinux { + return &ExLinux{} +} + +func (ex *ExLinux) TemperatureWithContext(ctx context.Context) ([]ExTemperature, error) { + var warns Warnings + + files, err := getTemperatureFiles(ctx) + if err != nil { + return nil, fmt.Errorf("failed to get temperature files, %w", err) + } + + temperatures := make([]ExTemperature, 0, len(files)) + for _, file := range files { + var raw []byte + + // Get the base directory location + directory := filepath.Dir(file) + + // Get the base filename prefix like temp1 + basename := strings.Split(filepath.Base(file), "_")[0] + + // Get the base path like /temp1 + basepath := filepath.Join(directory, basename) + + // Get the label of the temperature you are reading + label := "" + + if raw, _ = os.ReadFile(basepath + "_label"); len(raw) != 0 { + // Format the label from "Core 0" to "core_0" + label = strings.Join(strings.Split(strings.TrimSpace(strings.ToLower(string(raw))), " "), "_") + } + + // Get the name of the temperature you are reading + if raw, err = os.ReadFile(filepath.Join(directory, "name")); err != nil { + warns.Add(err) + continue + } + + name := strings.TrimSpace(string(raw)) + + if label != "" { + name = name + "_" + label + } + + // Add discovered temperature sensor to the list + temperatures = append(temperatures, ExTemperature{ + SensorKey: name, + Min: optionalValueReadFromFile(basepath+"_min") / hostTemperatureScale, + Lowest: optionalValueReadFromFile(basepath+"_lowest") / hostTemperatureScale, + Highest: optionalValueReadFromFile(basepath+"_highest") / hostTemperatureScale, + }) + } + + return temperatures, warns.Reference() +} diff --git a/sensors/sensors_linux.go b/sensors/sensors_linux.go index 85548f642..0e28ac044 100644 --- a/sensors/sensors_linux.go +++ b/sensors/sensors_linux.go @@ -5,6 +5,7 @@ package sensors import ( "context" + "fmt" "os" "path/filepath" "strconv" @@ -19,34 +20,20 @@ const ( ) func TemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) { - var err error - - var files []string - - temperatures := make([]TemperatureStat, 0) - - // Only the temp*_input file provides current temperature - // value in millidegree Celsius as reported by the temperature to the device: - // https://www.kernel.org/doc/Documentation/hwmon/sysfs-interface - if files, err = filepath.Glob(common.HostSysWithContext(ctx, "/class/hwmon/hwmon*/temp*_input")); err != nil { - return temperatures, err - } + var warns Warnings - if len(files) == 0 { - // CentOS has an intermediate /device directory: - // https://github.com/giampaolo/psutil/issues/971 - if files, err = filepath.Glob(common.HostSysWithContext(ctx, "/class/hwmon/hwmon*/device/temp*_input")); err != nil { - return temperatures, err - } + files, err := getTemperatureFiles(ctx) + if err != nil { + return nil, fmt.Errorf("failed to get tempreteure files, %w", err) } - var warns Warnings - if len(files) == 0 { // handle distributions without hwmon, like raspbian #391, parse legacy thermal_zone files files, err = filepath.Glob(common.HostSysWithContext(ctx, "/class/thermal/thermal_zone*/")) if err != nil { - return temperatures, err + return nil, err } + temperatures := make([]TemperatureStat, 0, len(files)) + for _, file := range files { // Get the name of the temperature you are reading name, err := os.ReadFile(filepath.Join(file, "type")) @@ -74,7 +61,7 @@ func TemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) { return temperatures, warns.Reference() } - temperatures = make([]TemperatureStat, 0, len(files)) + temperatures := make([]TemperatureStat, 0, len(files)) // example directory // device/ temp1_crit_alarm temp2_crit_alarm temp3_crit_alarm temp4_crit_alarm temp5_crit_alarm temp6_crit_alarm temp7_crit_alarm @@ -139,6 +126,29 @@ func TemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) { return temperatures, warns.Reference() } +func getTemperatureFiles(ctx context.Context) ([]string, error) { + var files []string + var err error + + // Only the temp*_input file provides current temperature + // value in millidegree Celsius as reported by the temperature to the device: + // https://www.kernel.org/doc/Documentation/hwmon/sysfs-interface + if files, err = filepath.Glob(common.HostSysWithContext(ctx, "/class/hwmon/hwmon*/temp*_input")); err != nil { + return nil, err + } + + if len(files) == 0 { + // CentOS has an intermediate /device directory: + // https://github.com/giampaolo/psutil/issues/971 + if files, err = filepath.Glob(common.HostSysWithContext(ctx, "/class/hwmon/hwmon*/device/temp*_input")); err != nil { + return nil, err + } + } + + return files, nil + +} + func optionalValueReadFromFile(filename string) float64 { var raw []byte