fix(agent): claim sensor names before filtering so excludes don't rename (#2645)

updateTemperatures detected duplicate SensorKeys by looking at the output
map, which only holds sensors that passed every filter. A sensor dropped by
SENSORS or SKIP_GPU therefore never claimed its name, so excluding the first
of two same-named sensors renamed the second one from nvme_sensor_2_4 to
nvme_sensor_2 and dropped it too, making it impossible to exclude just one.

Track handed-out names in a separate set that is populated before any filter
runs, so a sensor's key depends only on the hardware list.
This commit is contained in:
yi111
2026-10-19 13:09:05 -04:00
committed by GitHub
parent b431db751f
commit 574c4cf9dd
2 changed files with 60 additions and 5 deletions
+12 -5
View File
@@ -151,12 +151,24 @@ func (a *Agent) updateTemperatures(systemStats *system.Stats) {
}
systemStats.Temperatures = make(map[string]float64, len(temps))
// claimed tracks every name handed out, including names of sensors that are
// dropped below, so a sensor's key never depends on which sensors were filtered
claimed := make(map[string]struct{}, len(temps))
for i, sensor := range temps {
// check for malformed strings on darwin (gopsutil/issues/1832)
if runtime.GOOS == "darwin" && !utf8.ValidString(sensor.SensorKey) {
continue
}
// claim a name before any filtering, so excluding a sensor does not
// rename the sensors after it
sensorName := sensor.SensorKey
if _, ok := claimed[sensorName]; ok {
// if key already claimed, append int to key
sensorName = sensorName + "_" + strconv.Itoa(i)
}
claimed[sensorName] = struct{}{}
// scale temperature
if sensor.Temperature != 0 && sensor.Temperature < 1 {
sensor.Temperature = scaleTemperature(sensor.Temperature)
@@ -165,11 +177,6 @@ func (a *Agent) updateTemperatures(systemStats *system.Stats) {
if sensor.Temperature <= 0 || sensor.Temperature >= 200 {
continue
}
sensorName := sensor.SensorKey
if _, ok := systemStats.Temperatures[sensorName]; ok {
// if key already exists, append int to key
sensorName = sensorName + "_" + strconv.Itoa(i)
}
// skip if not in whitelist or blacklist
if !isValidSensor(sensorName, a.sensorConfig) {
continue
+48
View File
@@ -798,3 +798,51 @@ func TestUpdateTemperaturesSkipGpu(t *testing.T) {
newAgent(false).updateTemperatures(stats)
assert.Len(t, stats.Temperatures, 2)
}
func TestUpdateTemperaturesExcludedSensorKeepsNames(t *testing.T) {
originalGetSensorTemps := getSensorTemps
t.Cleanup(func() {
getSensorTemps = originalGetSensorTemps
})
// two drives that report the same SensorKey, plus an unrelated sensor
getSensorTemps = func(ctx context.Context) ([]sensors.TemperatureStat, error) {
return []sensors.TemperatureStat{
{SensorKey: "nvme_sensor_2", Temperature: 74.85},
{SensorKey: "nvme_sensor_2", Temperature: 41},
{SensorKey: "coretemp_core_0", Temperature: 55},
}, nil
}
newAgent := func(exclude string) *Agent {
config := map[string]struct{}{}
if exclude != "" {
config[exclude] = struct{}{}
}
return &Agent{
systemInfo: system.Info{},
sensorConfig: &SensorConfig{
context: context.Background(),
timeout: 2 * time.Second,
sensors: config,
isBlacklist: exclude != "",
},
}
}
// unfiltered: the second duplicate is suffixed with its index
stats := &system.Stats{}
newAgent("").updateTemperatures(stats)
assert.Equal(t, map[string]float64{
"nvme_sensor_2": 74.85,
"nvme_sensor_2_1": 41,
"coretemp_core_0": 55,
}, stats.Temperatures)
// excluding the first duplicate keeps the second one's name
stats = &system.Stats{}
newAgent("nvme_sensor_2").updateTemperatures(stats)
assert.Equal(t, map[string]float64{
"nvme_sensor_2_1": 41,
"coretemp_core_0": 55,
}, stats.Temperatures)
}