Skip to content

Commit

Permalink
[sensors][linux]: add ExLinux on sensors.
Browse files Browse the repository at this point in the history
This commit references and fixes #1589. Thank you!
  • Loading branch information
shirou committed Feb 24, 2024
1 parent 5419e3e commit d1a2a02
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 22 deletions.
79 changes: 79 additions & 0 deletions 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 <dir>/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()
}
54 changes: 32 additions & 22 deletions sensors/sensors_linux.go
Expand Up @@ -5,6 +5,7 @@ package sensors

import (
"context"
"fmt"
"os"
"path/filepath"
"strconv"
Expand All @@ -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"))
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down

0 comments on commit d1a2a02

Please sign in to comment.