Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion plugins/inputs/temp/temp_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@
package temp

import (
"errors"
"fmt"
"os"
"path/filepath"
"strconv"
"strings"

"golang.org/x/sys/unix"

"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/internal"
)
Expand Down Expand Up @@ -233,8 +236,12 @@ func (t *Temperature) gatherThermalZone(syspath string) ([]temperatureStat, erro
name := strings.TrimSpace(string(buf))

// Actual temperature
buf, err = os.ReadFile(filepath.Join(path, "temp"))
buf, err = readFileAsync(filepath.Join(path, "temp"))
if err != nil {
if errors.Is(err, unix.EAGAIN) || errors.Is(err, unix.EWOULDBLOCK) {
// Silently ignore this thermal-zone when the underlying hardware is unavailable
continue
}
t.Log.Errorf("Cannot read temperature of zone %q", path)
continue
}
Expand All @@ -249,3 +256,21 @@ func (t *Temperature) gatherThermalZone(syspath string) ([]temperatureStat, erro

return stats, nil
}

func readFileAsync(path string) ([]byte, error) {
fd, err := unix.Open(path, unix.O_RDONLY|unix.O_NONBLOCK, 0)
if err != nil {
return nil, err
}
defer unix.Close(fd)

// The kernal specifies the temparatures are expressed in millidegrees
// tempBuf of 8 bytes stores temperatures up-to 99999.999°C
var tempBuf [8]byte
Comment thread
01110111000001 marked this conversation as resolved.

n, err := unix.Read(fd, tempBuf[:])
if err != nil {
return nil, err
}
return tempBuf[:n], nil
}
71 changes: 71 additions & 0 deletions plugins/inputs/temp/temp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
package temp

import (
"bytes"
"fmt"
"os"
"path/filepath"
Expand All @@ -13,6 +14,7 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/shirou/gopsutil/v4/sensors"
"github.com/stretchr/testify/require"
"golang.org/x/sys/unix"

"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/config"
Expand Down Expand Up @@ -342,3 +344,72 @@ func sensorsTemperaturesOld(syspath string) ([]sensors.TemperatureStat, error) {
}
return temperatures, nil
}

func TestReadFileAsync(t *testing.T) {
normalFile := createFile(t, "normal.txt", []byte("45000\n"))
largeFile := createFile(t, "large.txt", []byte("9999999911"))
emptyFile := createFile(t, "empty.txt", make([]byte, 0))

// Setup Test 4: Named pipe (FIFO) to simulate EAGAIN
fifoFile := filepath.Join(t.TempDir(), "sensor_pipe")
require.NoError(t, unix.Mkfifo(fifoFile, 0666))

holdOpen, err := unix.Open(fifoFile, unix.O_RDWR|unix.O_NONBLOCK, 0)
require.NoError(t, err)

t.Cleanup(func() {
require.NoError(t, unix.Close(holdOpen))
})

tests := []struct {
name string
path string
expectedValue []byte
expectedError error
}{
{
name: "Valid file",
path: normalFile,
expectedValue: []byte("45000\n"),
expectedError: nil,
},
{
name: "File larger than 8 bytes (Truncation)",
path: largeFile,
expectedValue: bytes.Repeat([]byte("9"), 8),
expectedError: nil,
},
{
name: "Empty file",
path: emptyFile,
expectedValue: make([]byte, 0),
expectedError: nil,
},
{
name: "File does not exist",
path: filepath.Join(t.TempDir(), "missing.txt"),
expectedValue: nil,
expectedError: unix.ENOENT,
},
{
name: "Non-blocking read on empty pipe (EAGAIN)",
path: fifoFile,
expectedValue: nil,
expectedError: unix.EAGAIN,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotBytes, err := readFileAsync(tt.path)
require.ErrorIs(t, err, tt.expectedError)
require.Equal(t, tt.expectedValue, gotBytes)
})
}
}

func createFile(t *testing.T, name string, content []byte) string {
fileName := filepath.Join(t.TempDir(), name)
require.NoError(t, os.WriteFile(fileName, content, 0640))
return fileName
}
Loading