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