Adding upstream version 1.34.4.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
e393c3af3f
commit
4978089aab
4963 changed files with 677545 additions and 0 deletions
62
plugins/inputs/sensors/README.md
Normal file
62
plugins/inputs/sensors/README.md
Normal 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
|
||||
```
|
9
plugins/inputs/sensors/sample.conf
Normal file
9
plugins/inputs/sensors/sample.conf
Normal 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"
|
135
plugins/inputs/sensors/sensors.go
Normal file
135
plugins/inputs/sensors/sensors.go
Normal 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,
|
||||
}
|
||||
})
|
||||
}
|
33
plugins/inputs/sensors/sensors_notlinux.go
Normal file
33
plugins/inputs/sensors/sensors_notlinux.go
Normal 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{}
|
||||
})
|
||||
}
|
382
plugins/inputs/sensors/sensors_test.go
Normal file
382
plugins/inputs/sensors/sensors_test.go
Normal 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)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue