Skip to content

Commit 465fd94

Browse files
authored
Refactor class thermal error handling (#794)
Include any read errors when parsing /sys/class/thermal/thermal_zone data. This avoids premature error returns if there are platform specific problems like `temp` being unreadable, even tho it's a required file. Related to: prometheus/node_exporter#2980 Signed-off-by: SuperQ <superq@gmail.com>
1 parent b380dd4 commit 465fd94

File tree

2 files changed

+34
-36
lines changed

2 files changed

+34
-36
lines changed

sysfs/class_thermal.go

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,10 @@ package sysfs
1717

1818
import (
1919
"errors"
20+
"fmt"
2021
"os"
2122
"path/filepath"
2223
"strings"
23-
"syscall"
24-
25-
fsp "io/fs"
2624

2725
"github.com/prometheus/procfs/internal/util"
2826
)
@@ -37,6 +35,9 @@ type ClassThermalZoneStats struct {
3735
Policy string // One of the various thermal governors used for a particular zone.
3836
Mode *bool // Optional: One of the predefined values in [enabled, disabled].
3937
Passive *uint64 // Optional: millidegrees Celsius. (0 for disabled, > 1000 for enabled+value)
38+
39+
// ReadError contains any errors returned when gathering data.
40+
ReadErrors error
4041
}
4142

4243
// ClassThermalZoneStats returns Thermal Zone metrics for all zones.
@@ -48,39 +49,33 @@ func (fs FS) ClassThermalZoneStats() ([]ClassThermalZoneStats, error) {
4849

4950
stats := make([]ClassThermalZoneStats, 0, len(zones))
5051
for _, zone := range zones {
51-
zoneStats, err := parseClassThermalZone(zone)
52-
if err != nil {
53-
if errors.Is(err, syscall.ENODATA) || errors.As(err, new(*fsp.PathError)) || errors.Is(err, syscall.EAGAIN) ||
54-
errors.Is(err, syscall.EINVAL) {
55-
continue
56-
}
57-
return nil, err
58-
}
52+
zoneStats := parseClassThermalZone(zone)
5953
zoneStats.Name = strings.TrimPrefix(filepath.Base(zone), "thermal_zone")
6054
stats = append(stats, zoneStats)
6155
}
6256
return stats, nil
6357
}
6458

65-
func parseClassThermalZone(zone string) (ClassThermalZoneStats, error) {
59+
func parseClassThermalZone(zone string) ClassThermalZoneStats {
60+
var errs []error
6661
// Required attributes.
6762
zoneType, err := util.SysReadFile(filepath.Join(zone, "type"))
6863
if err != nil {
69-
return ClassThermalZoneStats{}, err
64+
errs = append(errs, fmt.Errorf("error reading type: %w", err))
7065
}
7166
zonePolicy, err := util.SysReadFile(filepath.Join(zone, "policy"))
7267
if err != nil {
73-
return ClassThermalZoneStats{}, err
68+
errs = append(errs, fmt.Errorf("error reading policy: %w", err))
7469
}
7570
zoneTemp, err := util.SysReadIntFromFile(filepath.Join(zone, "temp"))
76-
if err != nil {
77-
return ClassThermalZoneStats{}, err
71+
if err != nil && !errors.Is(err, os.ErrInvalid) {
72+
errs = append(errs, fmt.Errorf("error reading temp: %w", err))
7873
}
7974

8075
// Optional attributes.
8176
mode, err := util.SysReadFile(filepath.Join(zone, "mode"))
8277
if err != nil && !os.IsNotExist(err) && !os.IsPermission(err) {
83-
return ClassThermalZoneStats{}, err
78+
errs = append(errs, fmt.Errorf("error reading mode: %w", err))
8479
}
8580
zoneMode := util.ParseBool(mode)
8681

@@ -90,16 +85,17 @@ func parseClassThermalZone(zone string) (ClassThermalZoneStats, error) {
9085
case os.IsNotExist(err), os.IsPermission(err):
9186
zonePassive = nil
9287
case err != nil:
93-
return ClassThermalZoneStats{}, err
88+
errs = append(errs, fmt.Errorf("error reading passive: %w", err))
9489
default:
9590
zonePassive = &passive
9691
}
9792

9893
return ClassThermalZoneStats{
99-
Type: zoneType,
100-
Policy: zonePolicy,
101-
Temp: zoneTemp,
102-
Mode: zoneMode,
103-
Passive: zonePassive,
104-
}, nil
94+
Type: zoneType,
95+
Policy: zonePolicy,
96+
Temp: zoneTemp,
97+
Mode: zoneMode,
98+
Passive: zonePassive,
99+
ReadErrors: errors.Join(errs...),
100+
}
105101
}

sysfs/class_thermal_test.go

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,20 +39,22 @@ func TestClassThermalZoneStats(t *testing.T) {
3939

4040
classThermalZoneStats := []ClassThermalZoneStats{
4141
{
42-
Name: "0",
43-
Type: "bcm2835_thermal",
44-
Policy: "step_wise",
45-
Temp: 49925,
46-
Mode: nil,
47-
Passive: nil,
42+
Name: "0",
43+
Type: "bcm2835_thermal",
44+
Policy: "step_wise",
45+
Temp: 49925,
46+
Mode: nil,
47+
Passive: nil,
48+
ReadErrors: nil,
4849
},
4950
{
50-
Name: "1",
51-
Type: "acpitz",
52-
Policy: "step_wise",
53-
Temp: -44000,
54-
Mode: enabled,
55-
Passive: &passive,
51+
Name: "1",
52+
Type: "acpitz",
53+
Policy: "step_wise",
54+
Temp: -44000,
55+
Mode: enabled,
56+
Passive: &passive,
57+
ReadErrors: nil,
5658
},
5759
}
5860

0 commit comments

Comments
 (0)