Skip to content

Commit

Permalink
[sensors] move Temperatures from host to sensors.
Browse files Browse the repository at this point in the history
  • Loading branch information
shirou committed Feb 17, 2024
1 parent ca7dddf commit c6f7fad
Show file tree
Hide file tree
Showing 22 changed files with 371 additions and 272 deletions.
16 changes: 0 additions & 16 deletions host/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,6 @@ type UserStat struct {
Started int `json:"started"`
}

type TemperatureStat struct {
SensorKey string `json:"sensorKey"`
Temperature float64 `json:"temperature"`
High float64 `json:"sensorHigh"`
Critical float64 `json:"sensorCritical"`
}

func (h InfoStat) String() string {
s, _ := json.Marshal(h)
return string(s)
Expand All @@ -58,11 +51,6 @@ func (u UserStat) String() string {
return string(s)
}

func (t TemperatureStat) String() string {
s, _ := json.Marshal(t)
return string(s)
}

var enableBootTimeCache bool

// EnableBootTimeCache change cache behavior of BootTime. If true, cache BootTime value. Default is false.
Expand Down Expand Up @@ -158,10 +146,6 @@ func KernelVersion() (string, error) {
return KernelVersionWithContext(context.Background())
}

func SensorsTemperatures() ([]TemperatureStat, error) {
return SensorsTemperaturesWithContext(context.Background())
}

func timeSince(ts uint64) uint64 {
return uint64(time.Now().Unix()) - ts
}
Expand Down
4 changes: 0 additions & 4 deletions host/host_fallback.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,6 @@ func PlatformInformationWithContext(ctx context.Context) (string, string, string
return "", "", "", common.ErrNotImplementedError
}

func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) {
return []TemperatureStat{}, common.ErrNotImplementedError
}

func KernelArch() (string, error) {
return "", common.ErrNotImplementedError
}
4 changes: 0 additions & 4 deletions host/host_freebsd.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,6 @@ func getUsersFromUtmp(utmpfile string) ([]UserStat, error) {
return ret, nil
}

func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) {
return []TemperatureStat{}, common.ErrNotImplementedError
}

func KernelVersionWithContext(ctx context.Context) (string, error) {
_, _, version, err := PlatformInformationWithContext(ctx)
return version, err
Expand Down
148 changes: 0 additions & 148 deletions host/host_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@ import (
"fmt"
"io"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"

"golang.org/x/sys/unix"
Expand All @@ -30,8 +28,6 @@ type lsbStruct struct {
// from utmp.h
const (
user_PROCESS = 7

hostTemperatureScale = 1000.0
)

func HostIDWithContext(ctx context.Context) (string, error) {
Expand Down Expand Up @@ -392,147 +388,3 @@ func getSusePlatform(contents []string) string {
func VirtualizationWithContext(ctx context.Context) (string, string, error) {
return common.VirtualizationWithContext(ctx)
}

func SensorsTemperaturesWithContext(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
}

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
}
}

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
}
for _, file := range files {
// Get the name of the temperature you are reading
name, err := os.ReadFile(filepath.Join(file, "type"))
if err != nil {
warns.Add(err)
continue
}
// Get the temperature reading
current, err := os.ReadFile(filepath.Join(file, "temp"))
if err != nil {
warns.Add(err)
continue
}
temperature, err := strconv.ParseInt(strings.TrimSpace(string(current)), 10, 64)
if err != nil {
warns.Add(err)
continue
}

temperatures = append(temperatures, TemperatureStat{
SensorKey: strings.TrimSpace(string(name)),
Temperature: float64(temperature) / 1000.0,
})
}
return temperatures, warns.Reference()
}

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
// name temp1_input temp2_input temp3_input temp4_input temp5_input temp6_input temp7_input
// power/ temp1_label temp2_label temp3_label temp4_label temp5_label temp6_label temp7_label
// subsystem/ temp1_max temp2_max temp3_max temp4_max temp5_max temp6_max temp7_max
// temp1_crit temp2_crit temp3_crit temp4_crit temp5_crit temp6_crit temp7_crit uevent
for _, file := range files {
var raw []byte

var temperature float64

// 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
}

// Get the temperature reading
if raw, err = os.ReadFile(file); err != nil {
warns.Add(err)
continue
}

if temperature, err = strconv.ParseFloat(strings.TrimSpace(string(raw)), 64); err != nil {
warns.Add(err)
continue
}

// Add discovered temperature sensor to the list
temperatures = append(temperatures, TemperatureStat{
SensorKey: name,
Temperature: temperature / hostTemperatureScale,
High: optionalValueReadFromFile(basepath+"_max") / hostTemperatureScale,
Critical: optionalValueReadFromFile(basepath+"_crit") / hostTemperatureScale,
})
}

return temperatures, warns.Reference()
}

func optionalValueReadFromFile(filename string) float64 {
var raw []byte

var err error

var value float64

// Check if file exists
if _, err := os.Stat(filename); os.IsNotExist(err) {
return 0
}

if raw, err = os.ReadFile(filename); err != nil {
return 0
}

if value, err = strconv.ParseFloat(strings.TrimSpace(string(raw)), 64); err != nil {
return 0
}

return value
}
4 changes: 0 additions & 4 deletions host/host_netbsd.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,6 @@ func UsersWithContext(ctx context.Context) ([]UserStat, error) {
return ret, common.ErrNotImplementedError
}

func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) {
return []TemperatureStat{}, common.ErrNotImplementedError
}

func KernelVersionWithContext(ctx context.Context) (string, error) {
_, _, version, err := PlatformInformationWithContext(ctx)
return version, err
Expand Down
4 changes: 0 additions & 4 deletions host/host_openbsd.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,6 @@ func UsersWithContext(ctx context.Context) ([]UserStat, error) {
return ret, nil
}

func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) {
return []TemperatureStat{}, common.ErrNotImplementedError
}

func KernelVersionWithContext(ctx context.Context) (string, error) {
_, _, version, err := PlatformInformationWithContext(ctx)
return version, err
Expand Down
41 changes: 2 additions & 39 deletions host/host_solaris.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// SPDX-License-Identifier: BSD-3-Clause
//go:build solaris

package host

import (
"bufio"
"bytes"
"context"
"encoding/csv"
"fmt"
"io"
"os"
"regexp"
"strconv"
Expand Down Expand Up @@ -95,43 +95,6 @@ func UsersWithContext(ctx context.Context) ([]UserStat, error) {
return []UserStat{}, common.ErrNotImplementedError
}

func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) {
var ret []TemperatureStat

out, err := invoke.CommandWithContext(ctx, "ipmitool", "-c", "sdr", "list")
if err != nil {
return ret, err
}

r := csv.NewReader(strings.NewReader(string(out)))
// Output may contain errors, e.g. "bmc_send_cmd: Permission denied", don't expect a consistent number of records
r.FieldsPerRecord = -1
for {
record, err := r.Read()
if err == io.EOF {
break
}
if err != nil {
return ret, err
}
// CPU1 Temp,40,degrees C,ok
if len(record) < 3 || record[1] == "" || record[2] != "degrees C" {
continue
}
v, err := strconv.ParseFloat(record[1], 64)
if err != nil {
return ret, err
}
ts := TemperatureStat{
SensorKey: strings.TrimSuffix(record[0], " Temp"),
Temperature: v,
}
ret = append(ret, ts)
}

return ret, nil
}

func VirtualizationWithContext(ctx context.Context) (string, string, error) {
return "", "", common.ErrNotImplementedError
}
Expand Down
13 changes: 0 additions & 13 deletions host/host_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,19 +137,6 @@ func TestHostGuid(t *testing.T) {
}
}

func TestTemperatureStat_String(t *testing.T) {
v := TemperatureStat{
SensorKey: "CPU",
Temperature: 1.1,
High: 30.1,
Critical: 0.1,
}
s := `{"sensorKey":"CPU","temperature":1.1,"sensorHigh":30.1,"sensorCritical":0.1}`
if s != fmt.Sprintf("%v", v) {
t.Errorf("TemperatureStat string is invalid, %v", fmt.Sprintf("%v", v))
}
}

func TestVirtualization(t *testing.T) {
wg := sync.WaitGroup{}
testCount := 10
Expand Down
36 changes: 0 additions & 36 deletions host/host_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ package host
import (
"context"
"fmt"
"math"
"strconv"
"strings"
"sync/atomic"
Expand All @@ -16,7 +15,6 @@ import (

"github.com/shirou/gopsutil/v4/internal/common"
"github.com/shirou/gopsutil/v4/process"
"github.com/yusufpapurcu/wmi"
"golang.org/x/sys/windows"
)

Expand Down Expand Up @@ -57,13 +55,6 @@ type systemInfo struct {
wProcessorRevision uint16
}

type msAcpi_ThermalZoneTemperature struct {
Active bool
CriticalTripPoint uint32
CurrentTemperature uint32
InstanceName string
}

func HostIDWithContext(ctx context.Context) (string, error) {
// there has been reports of issues on 32bit using golang.org/x/sys/windows/registry, see https://github.com/shirou/gopsutil/pull/312#issuecomment-277422612
// for rationale of using windows.RegOpenKeyEx/RegQueryValueEx instead of registry.OpenKey/GetStringValue
Expand Down Expand Up @@ -232,33 +223,6 @@ func UsersWithContext(ctx context.Context) ([]UserStat, error) {
return ret, common.ErrNotImplementedError
}

func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) {
var ret []TemperatureStat
var dst []msAcpi_ThermalZoneTemperature
q := wmi.CreateQuery(&dst, "")
if err := common.WMIQueryWithContext(ctx, q, &dst, nil, "root/wmi"); err != nil {
return ret, err
}

for _, v := range dst {
ts := TemperatureStat{
SensorKey: v.InstanceName,
Temperature: kelvinToCelsius(v.CurrentTemperature, 2),
}
ret = append(ret, ts)
}

return ret, nil
}

func kelvinToCelsius(temp uint32, n int) float64 {
// wmi return temperature Kelvin * 10, so need to divide the result by 10,
// and then minus 273.15 to get °Celsius.
t := float64(temp/10) - 273.15
n10 := math.Pow10(n)
return math.Trunc((t+0.5/n10)*n10) / n10
}

func VirtualizationWithContext(ctx context.Context) (string, string, error) {
return "", "", common.ErrNotImplementedError
}
Expand Down
Loading

0 comments on commit c6f7fad

Please sign in to comment.