1
0
Fork 0

Adding upstream version 1.34.4.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-05-24 07:26:29 +02:00
parent e393c3af3f
commit 4978089aab
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
4963 changed files with 677545 additions and 0 deletions

View file

@ -0,0 +1,62 @@
# LM Sensors Input Plugin
Collect [lm-sensors](https://en.wikipedia.org/wiki/Lm_sensors) metrics -
requires the lm-sensors package installed.
This plugin collects sensor metrics with the `sensors` executable from the
lm-sensor package.
## Global configuration options <!-- @/docs/includes/plugin_config.md -->
In addition to the plugin-specific configuration settings, plugins support
additional global and plugin configuration settings. These settings are used to
modify metrics, tags, and field or create aliases and configure ordering, etc.
See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins
## Configuration
```toml @sample.conf
# Monitor sensors, requires lm-sensors package
# This plugin ONLY supports Linux
[[inputs.sensors]]
## Remove numbers from field names.
## If true, a field name like 'temp1_input' will be changed to 'temp_input'.
# remove_numbers = true
## Timeout is the maximum amount of time that the sensors command can run.
# timeout = "5s"
```
## Metrics
Fields are created dynamically depending on the sensors. All fields are float.
### Tags
- All measurements have the following tags:
- chip
- feature
## Example Output
### Default
```text
sensors,chip=power_meter-acpi-0,feature=power1 power_average=0,power_average_interval=300 1466751326000000000
sensors,chip=k10temp-pci-00c3,feature=temp1 temp_crit=70,temp_crit_hyst=65,temp_input=29,temp_max=70 1466751326000000000
sensors,chip=k10temp-pci-00cb,feature=temp1 temp_input=29,temp_max=70 1466751326000000000
sensors,chip=k10temp-pci-00d3,feature=temp1 temp_input=27.5,temp_max=70 1466751326000000000
sensors,chip=k10temp-pci-00db,feature=temp1 temp_crit=70,temp_crit_hyst=65,temp_input=29.5,temp_max=70 1466751326000000000
```
### With remove_numbers=false
```text
sensors,chip=power_meter-acpi-0,feature=power1 power1_average=0,power1_average_interval=300 1466753424000000000
sensors,chip=k10temp-pci-00c3,feature=temp1 temp1_crit=70,temp1_crit_hyst=65,temp1_input=29.125,temp1_max=70 1466753424000000000
sensors,chip=k10temp-pci-00cb,feature=temp1 temp1_input=29,temp1_max=70 1466753424000000000
sensors,chip=k10temp-pci-00d3,feature=temp1 temp1_input=29.5,temp1_max=70 1466753424000000000
sensors,chip=k10temp-pci-00db,feature=temp1 temp1_crit=70,temp1_crit_hyst=65,temp1_input=30,temp1_max=70 1466753424000000000
```

View file

@ -0,0 +1,9 @@
# Monitor sensors, requires lm-sensors package
# This plugin ONLY supports Linux
[[inputs.sensors]]
## Remove numbers from field names.
## If true, a field name like 'temp1_input' will be changed to 'temp_input'.
# remove_numbers = true
## Timeout is the maximum amount of time that the sensors command can run.
# timeout = "5s"

View file

@ -0,0 +1,135 @@
//go:generate ../../../tools/readme_config_includer/generator
//go:build linux
package sensors
import (
_ "embed"
"errors"
"fmt"
"os/exec"
"regexp"
"strconv"
"strings"
"time"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/config"
"github.com/influxdata/telegraf/internal"
"github.com/influxdata/telegraf/plugins/inputs"
)
//go:embed sample.conf
var sampleConfig string
var (
execCommand = exec.Command // execCommand is used to mock commands in tests.
numberRegp = regexp.MustCompile("[0-9]+")
defaultTimeout = config.Duration(5 * time.Second)
)
const cmd = "sensors"
type Sensors struct {
RemoveNumbers bool `toml:"remove_numbers"`
Timeout config.Duration `toml:"timeout"`
path string
}
func (*Sensors) SampleConfig() string {
return sampleConfig
}
func (s *Sensors) Init() error {
// Set defaults
if s.path == "" {
path, err := exec.LookPath(cmd)
if err != nil {
return fmt.Errorf("looking up %q failed: %w", cmd, err)
}
s.path = path
}
// Check parameters
if s.path == "" {
return fmt.Errorf("no path specified for %q", cmd)
}
return nil
}
func (s *Sensors) Gather(acc telegraf.Accumulator) error {
if len(s.path) == 0 {
return errors.New("sensors not found: verify that lm-sensors package is installed and that sensors is in your PATH")
}
return s.parse(acc)
}
// parse forks the command:
//
// sensors -u -A
//
// and parses the output to add it to the telegraf.Accumulator.
func (s *Sensors) parse(acc telegraf.Accumulator) error {
tags := make(map[string]string)
fields := make(map[string]interface{})
chip := ""
cmd := execCommand(s.path, "-A", "-u")
out, err := internal.StdOutputTimeout(cmd, time.Duration(s.Timeout))
if err != nil {
return fmt.Errorf("failed to run command %q: %w - %s", strings.Join(cmd.Args, " "), err, string(out))
}
lines := strings.Split(strings.TrimSpace(string(out)), "\n")
for _, line := range lines {
if len(line) == 0 {
acc.AddFields("sensors", fields, tags)
chip = ""
tags = make(map[string]string)
fields = make(map[string]interface{})
continue
}
if len(chip) == 0 {
chip = line
tags["chip"] = chip
continue
}
if !strings.HasPrefix(line, " ") {
if len(tags) > 1 {
acc.AddFields("sensors", fields, tags)
}
fields = make(map[string]interface{})
tags = map[string]string{
"chip": chip,
"feature": strings.TrimRight(snake(line), ":"),
}
} else {
splitted := strings.Split(line, ":")
fieldName := strings.TrimSpace(splitted[0])
if s.RemoveNumbers {
fieldName = numberRegp.ReplaceAllString(fieldName, "")
}
fieldValue, err := strconv.ParseFloat(strings.TrimSpace(splitted[1]), 64)
if err != nil {
return err
}
fields[fieldName] = fieldValue
}
}
acc.AddFields("sensors", fields, tags)
return nil
}
// snake converts string to snake case
func snake(input string) string {
return strings.ToLower(strings.ReplaceAll(strings.TrimSpace(input), " ", "_"))
}
func init() {
inputs.Add("sensors", func() telegraf.Input {
return &Sensors{
RemoveNumbers: true,
Timeout: defaultTimeout,
}
})
}

View file

@ -0,0 +1,33 @@
//go:generate ../../../tools/readme_config_includer/generator
//go:build !linux
package sensors
import (
_ "embed"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/inputs"
)
//go:embed sample.conf
var sampleConfig string
type Sensors struct {
Log telegraf.Logger `toml:"-"`
}
func (*Sensors) SampleConfig() string { return sampleConfig }
func (s *Sensors) Init() error {
s.Log.Warn("Current platform is not supported")
return nil
}
func (*Sensors) Gather(telegraf.Accumulator) error { return nil }
func init() {
inputs.Add("sensors", func() telegraf.Input {
return &Sensors{}
})
}

View file

@ -0,0 +1,382 @@
//go:build linux
package sensors
import (
"fmt"
"os"
"os/exec"
"testing"
"github.com/stretchr/testify/require"
"github.com/influxdata/telegraf/testutil"
)
func TestGatherDefault(t *testing.T) {
s := Sensors{
RemoveNumbers: true,
Timeout: defaultTimeout,
path: "sensors",
}
// overwriting exec commands with mock commands
execCommand = fakeExecCommand
defer func() { execCommand = exec.Command }()
var acc testutil.Accumulator
require.NoError(t, s.Init())
require.NoError(t, s.Gather(&acc))
var tests = []struct {
tags map[string]string
fields map[string]interface{}
}{
{
map[string]string{
"chip": "acpitz-virtual-0",
"feature": "temp1",
},
map[string]interface{}{
"temp_input": 8.3,
"temp_crit": 31.3,
},
},
{
map[string]string{
"chip": "power_meter-acpi-0",
"feature": "power1",
},
map[string]interface{}{
"power_average": 0.0,
"power_average_interval": 300.0,
},
},
{
map[string]string{
"chip": "coretemp-isa-0000",
"feature": "physical_id_0",
},
map[string]interface{}{
"temp_input": 77.0,
"temp_max": 82.0,
"temp_crit": 92.0,
"temp_crit_alarm": 0.0,
},
},
{
map[string]string{
"chip": "coretemp-isa-0000",
"feature": "core_0",
},
map[string]interface{}{
"temp_input": 75.0,
"temp_max": 82.0,
"temp_crit": 92.0,
"temp_crit_alarm": 0.0,
},
},
{
map[string]string{
"chip": "coretemp-isa-0000",
"feature": "core_1",
},
map[string]interface{}{
"temp_input": 77.0,
"temp_max": 82.0,
"temp_crit": 92.0,
"temp_crit_alarm": 0.0,
},
},
{
map[string]string{
"chip": "coretemp-isa-0001",
"feature": "physical_id_1",
},
map[string]interface{}{
"temp_input": 70.0,
"temp_max": 82.0,
"temp_crit": 92.0,
"temp_crit_alarm": 0.0,
},
},
{
map[string]string{
"chip": "coretemp-isa-0001",
"feature": "core_0",
},
map[string]interface{}{
"temp_input": 66.0,
"temp_max": 82.0,
"temp_crit": 92.0,
"temp_crit_alarm": 0.0,
},
},
{
map[string]string{
"chip": "coretemp-isa-0001",
"feature": "core_1",
},
map[string]interface{}{
"temp_input": 70.0,
"temp_max": 82.0,
"temp_crit": 92.0,
"temp_crit_alarm": 0.0,
},
},
{
map[string]string{
"chip": "atk0110-acpi-0",
"feature": "vcore_voltage",
},
map[string]interface{}{
"in_input": 1.136,
"in_min": 0.800,
"in_max": 1.600,
},
},
{
map[string]string{
"chip": "atk0110-acpi-0",
"feature": "+3.3_voltage",
},
map[string]interface{}{
"in_input": 3.360,
"in_min": 2.970,
"in_max": 3.630,
},
},
}
for _, test := range tests {
acc.AssertContainsTaggedFields(t, "sensors", test.fields, test.tags)
}
}
func TestGatherNotRemoveNumbers(t *testing.T) {
s := Sensors{
RemoveNumbers: false,
Timeout: defaultTimeout,
path: "sensors",
}
// overwriting exec commands with mock commands
execCommand = fakeExecCommand
defer func() { execCommand = exec.Command }()
var acc testutil.Accumulator
require.NoError(t, s.Init())
require.NoError(t, s.Gather(&acc))
var tests = []struct {
tags map[string]string
fields map[string]interface{}
}{
{
map[string]string{
"chip": "acpitz-virtual-0",
"feature": "temp1",
},
map[string]interface{}{
"temp1_input": 8.3,
"temp1_crit": 31.3,
},
},
{
map[string]string{
"chip": "power_meter-acpi-0",
"feature": "power1",
},
map[string]interface{}{
"power1_average": 0.0,
"power1_average_interval": 300.0,
},
},
{
map[string]string{
"chip": "coretemp-isa-0000",
"feature": "physical_id_0",
},
map[string]interface{}{
"temp1_input": 77.0,
"temp1_max": 82.0,
"temp1_crit": 92.0,
"temp1_crit_alarm": 0.0,
},
},
{
map[string]string{
"chip": "coretemp-isa-0000",
"feature": "core_0",
},
map[string]interface{}{
"temp2_input": 75.0,
"temp2_max": 82.0,
"temp2_crit": 92.0,
"temp2_crit_alarm": 0.0,
},
},
{
map[string]string{
"chip": "coretemp-isa-0000",
"feature": "core_1",
},
map[string]interface{}{
"temp3_input": 77.0,
"temp3_max": 82.0,
"temp3_crit": 92.0,
"temp3_crit_alarm": 0.0,
},
},
{
map[string]string{
"chip": "coretemp-isa-0001",
"feature": "physical_id_1",
},
map[string]interface{}{
"temp1_input": 70.0,
"temp1_max": 82.0,
"temp1_crit": 92.0,
"temp1_crit_alarm": 0.0,
},
},
{
map[string]string{
"chip": "coretemp-isa-0001",
"feature": "core_0",
},
map[string]interface{}{
"temp2_input": 66.0,
"temp2_max": 82.0,
"temp2_crit": 92.0,
"temp2_crit_alarm": 0.0,
},
},
{
map[string]string{
"chip": "coretemp-isa-0001",
"feature": "core_1",
},
map[string]interface{}{
"temp3_input": 70.0,
"temp3_max": 82.0,
"temp3_crit": 92.0,
"temp3_crit_alarm": 0.0,
},
},
{
map[string]string{
"chip": "atk0110-acpi-0",
"feature": "vcore_voltage",
},
map[string]interface{}{
"in0_input": 1.136,
"in0_min": 0.800,
"in0_max": 1.600,
},
},
{
map[string]string{
"chip": "atk0110-acpi-0",
"feature": "+3.3_voltage",
},
map[string]interface{}{
"in1_input": 3.360,
"in1_min": 2.970,
"in1_max": 3.630,
},
},
}
for _, test := range tests {
acc.AssertContainsTaggedFields(t, "sensors", test.fields, test.tags)
}
}
// fakeExecCommand is a helper function that mock
// the exec.Command call (and call the test binary)
func fakeExecCommand(command string, args ...string) *exec.Cmd {
cs := []string{"-test.run=TestHelperProcess", "--", command}
cs = append(cs, args...)
cmd := exec.Command(os.Args[0], cs...)
cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
return cmd
}
// TestHelperProcess isn't a real test. It's used to mock exec.Command
// For example, if you run:
// GO_WANT_HELPER_PROCESS=1 go test -test.run=TestHelperProcess -- chrony tracking
// it returns below mockData.
func TestHelperProcess(*testing.T) {
if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
return
}
mockData := `acpitz-virtual-0
temp1:
temp1_input: 8.300
temp1_crit: 31.300
power_meter-acpi-0
power1:
power1_average: 0.000
power1_average_interval: 300.000
coretemp-isa-0000
Physical id 0:
temp1_input: 77.000
temp1_max: 82.000
temp1_crit: 92.000
temp1_crit_alarm: 0.000
Core 0:
temp2_input: 75.000
temp2_max: 82.000
temp2_crit: 92.000
temp2_crit_alarm: 0.000
Core 1:
temp3_input: 77.000
temp3_max: 82.000
temp3_crit: 92.000
temp3_crit_alarm: 0.000
coretemp-isa-0001
Physical id 1:
temp1_input: 70.000
temp1_max: 82.000
temp1_crit: 92.000
temp1_crit_alarm: 0.000
Core 0:
temp2_input: 66.000
temp2_max: 82.000
temp2_crit: 92.000
temp2_crit_alarm: 0.000
Core 1:
temp3_input: 70.000
temp3_max: 82.000
temp3_crit: 92.000
temp3_crit_alarm: 0.000
atk0110-acpi-0
Vcore Voltage:
in0_input: 1.136
in0_min: 0.800
in0_max: 1.600
+3.3 Voltage:
in1_input: 3.360
in1_min: 2.970
in1_max: 3.630
`
args := os.Args
// Previous arguments are tests stuff, that looks like :
// /tmp/go-build970079519/…/_test/integration.test -test.run=TestHelperProcess --
cmd, _ := args[3], args[4:]
if cmd != "sensors" {
fmt.Fprint(os.Stdout, "command not found")
//nolint:revive // error code is important for this "test"
os.Exit(1)
}
fmt.Fprint(os.Stdout, mockData)
//nolint:revive // error code is important for this "test"
os.Exit(0)
}