diff options
Diffstat (limited to 'src')
15 files changed, 882 insertions, 0 deletions
diff --git a/src/go/collectors/go.d.plugin/config/go.d.conf b/src/go/collectors/go.d.plugin/config/go.d.conf index ab3a5aca74..9fe91db5d9 100644 --- a/src/go/collectors/go.d.plugin/config/go.d.conf +++ b/src/go/collectors/go.d.plugin/config/go.d.conf @@ -39,6 +39,7 @@ modules: # fluentd: yes # freeradius: yes # haproxy: yes +# hddtemp: yes # hdfs: yes # httpcheck: yes # intelgpu: yes diff --git a/src/go/collectors/go.d.plugin/config/go.d/hddtemp.conf b/src/go/collectors/go.d.plugin/config/go.d/hddtemp.conf new file mode 100644 index 0000000000..a2ea8452d3 --- /dev/null +++ b/src/go/collectors/go.d.plugin/config/go.d/hddtemp.conf @@ -0,0 +1,6 @@ +## All available configuration options, their descriptions and default values: +## https://github.com/netdata/netdata/tree/master/src/go/collectors/go.d.plugin/modules/hddtemp#readme + +#jobs: +# - name: local +# address: 127.0.0.1:7634 diff --git a/src/go/collectors/go.d.plugin/config/go.d/sd/net_listeners.conf b/src/go/collectors/go.d.plugin/config/go.d/sd/net_listeners.conf index 1c240ce5b6..6c2e22c71c 100644 --- a/src/go/collectors/go.d.plugin/config/go.d/sd/net_listeners.conf +++ b/src/go/collectors/go.d.plugin/config/go.d/sd/net_listeners.conf @@ -50,6 +50,8 @@ classify: expr: '{{ and (eq .Port "6060") (eq .Comm "geth") }}' - tags: "haproxy" expr: '{{ and (eq .Port "8404") (eq .Comm "haproxy") }}' + - tags: "hddtemp" + expr: '{{ and (eq .Port "7634") (eq .Comm "hddtemp") }}' - tags: "hdfs_namenode" expr: '{{ and (eq .Port "9870") (eq .Comm "hadoop") }}' - tags: "hdfs_datanode" @@ -226,6 +228,11 @@ compose: module: haproxy name: local url: http://{{.Address}}/metrics + - selector: "hddtemp" + template: | + module: hddtemp + name: local + address: {{.Address}} - selector: "hdfs_namenode" template: | module: hdfs diff --git a/src/go/collectors/go.d.plugin/modules/hddtemp/charts.go b/src/go/collectors/go.d.plugin/modules/hddtemp/charts.go new file mode 100644 index 0000000000..7a5e9ed9f4 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/hddtemp/charts.go @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package hddtemp + +import ( + "fmt" + "strings" + + "github.com/netdata/netdata/go/go.d.plugin/agent/module" +) + +const ( + prioDiskTemperature = module.Priority + iota + prioDiskTemperatureSensorStatus +) + +var ( + diskTemperatureChartsTmpl = module.Chart{ + ID: "disk_%s_temperature", + Title: "Disk temperature", + Units: "Celsius", + Fam: "temperature", + Ctx: "hddtemp.disk_temperature", + Type: module.Line, + Priority: prioDiskTemperature, + Dims: module.Dims{ + {ID: "disk_%s_temperature", Name: "temperature"}, + }, + } + diskTemperatureSensorChartsTmpl = module.Chart{ + ID: "disk_%s_temperature_sensor_status", + Title: "Disk temperature sensor status", + Units: "status", + Fam: "sensor", + Ctx: "hddtemp.disk_temperature_sensor_status", + Type: module.Line, + Priority: prioDiskTemperatureSensorStatus, + Dims: module.Dims{ + {ID: "disk_%s_temp_sensor_status_ok", Name: "ok"}, + {ID: "disk_%s_temp_sensor_status_err", Name: "err"}, + {ID: "disk_%s_temp_sensor_status_na", Name: "na"}, + {ID: "disk_%s_temp_sensor_status_unk", Name: "unk"}, + {ID: "disk_%s_temp_sensor_status_nos", Name: "nos"}, + {ID: "disk_%s_temp_sensor_status_slp", Name: "slp"}, + }, + } +) + +func (h *HddTemp) addDiskTempSensorStatusChart(id string, disk diskStats) { + h.addDiskChart(id, disk, diskTemperatureSensorChartsTmpl.Copy()) +} + +func (h *HddTemp) addDiskTempChart(id string, disk diskStats) { + h.addDiskChart(id, disk, diskTemperatureChartsTmpl.Copy()) +} + +func (h *HddTemp) addDiskChart(id string, disk diskStats, chart *module.Chart) { + chart.ID = fmt.Sprintf(chart.ID, strings.ToLower(id)) + chart.Labels = []module.Label{ + {Key: "disk_id", Value: id}, + {Key: "model", Value: disk.model}, + } + for _, dim := range chart.Dims { + dim.ID = fmt.Sprintf(dim.ID, id) + } + + if err := h.Charts().Add(chart); err != nil { + h.Warning(err) + } +} diff --git a/src/go/collectors/go.d.plugin/modules/hddtemp/client.go b/src/go/collectors/go.d.plugin/modules/hddtemp/client.go new file mode 100644 index 0000000000..626381ee86 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/hddtemp/client.go @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package hddtemp + +import ( + "github.com/netdata/netdata/go/go.d.plugin/pkg/socket" +) + +func newHddTempConn(conf Config) hddtempConn { + return &hddtempClient{conn: socket.New(socket.Config{ + Address: conf.Address, + ConnectTimeout: conf.Timeout.Duration(), + ReadTimeout: conf.Timeout.Duration(), + WriteTimeout: conf.Timeout.Duration(), + })} +} + +type hddtempClient struct { + conn socket.Client +} + +func (c *hddtempClient) connect() error { + return c.conn.Connect() +} + +func (c *hddtempClient) disconnect() { + _ = c.conn.Disconnect() +} + +func (c *hddtempClient) queryHddTemp() (string, error) { + var i int + var s string + err := c.conn.Command("", func(bytes []byte) bool { + if i++; i > 1 { + return false + } + s = string(bytes) + return true + }) + if err != nil { + return "", err + } + return s, nil +} diff --git a/src/go/collectors/go.d.plugin/modules/hddtemp/collect.go b/src/go/collectors/go.d.plugin/modules/hddtemp/collect.go new file mode 100644 index 0000000000..f5c75db041 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/hddtemp/collect.go @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package hddtemp + +import ( + "errors" + "fmt" + "strconv" + "strings" +) + +type diskStats struct { + devPath string + model string + temperature string + unit string +} + +func (h *HddTemp) collect() (map[string]int64, error) { + conn := h.newHddTempConn(h.Config) + + if err := conn.connect(); err != nil { + return nil, err + } + + defer conn.disconnect() + + msg, err := conn.queryHddTemp() + if err != nil { + return nil, err + } + + h.Debugf("hddtemp daemon response: %s", msg) + + disks, err := parseHddTempMessage(msg) + if err != nil { + return nil, err + } + + mx := make(map[string]int64) + + for _, disk := range disks { + id := getDiskID(disk) + if id == "" { + h.Debugf("can not extract disk id from '%s'", disk.devPath) + continue + } + + if !h.disks[id] { + h.disks[id] = true + h.addDiskTempSensorStatusChart(id, disk) + } + + px := fmt.Sprintf("disk_%s_", id) + + for _, st := range []string{"ok", "na", "unk", "nos", "slp", "err"} { + mx[px+"temp_sensor_status_"+st] = 0 + } + switch disk.temperature { + case "NA": + mx[px+"temp_sensor_status_na"] = 1 + case "UNK": + mx[px+"temp_sensor_status_unk"] = 1 + case "NOS": + mx[px+"temp_sensor_status_nos"] = 1 + case "SLP": + mx[px+"temp_sensor_status_slp"] = 1 + case "ERR": + mx[px+"temp_sensor_status_err"] = 1 + default: + if v, ok := getTemperature(disk); ok { + if !h.disksTemp[id] { + h.disksTemp[id] = true + h.addDiskTempChart(id, disk) + } + mx[px+"temp_sensor_status_ok"] = 1 + mx[px+"temperature"] = v + } else { + mx[px+"temp_sensor_status_unk"] = 1 + } + } + } + + return mx, nil +} + +func getDiskID(d diskStats) string { + i := strings.LastIndexByte(d.devPath, '/') + if i == -1 { + return "" + } + return d.devPath[i+1:] +} + +func getTemperature(d diskStats) (int64, bool) { + v, err := strconv.ParseInt(d.temperature, 10, 64) + if err != nil { + return 0, false + } + if d.unit == "F" { + v = (v - 32) * 5 / 9 + } + return v, true +} + +func parseHddTempMessage(msg string) ([]diskStats, error) { + if msg == "" { + return nil, errors.New("empty hddtemp message") + } + + // https://github.com/guzu/hddtemp/blob/e16aed6d0145d7ad8b3308dd0b9199fc701c0417/src/daemon.c#L165 + parts := strings.Split(msg, "|") + + var i int + // remove empty values + for _, v := range parts { + if v = strings.TrimSpace(v); v != "" { + parts[i] = v + i++ + } + } + parts = parts[:i] + + if len(parts) == 0 || len(parts)%4 != 0 { + return nil, errors.New("invalid hddtemp output format") + } + + var disks []diskStats + + for i := 0; i < len(parts); i += 4 { + disks = append(disks, diskStats{ + devPath: parts[i], + model: parts[i+1], + temperature: parts[i+2], + unit: parts[i+3], + }) + } + + return disks, nil +} diff --git a/src/go/collectors/go.d.plugin/modules/hddtemp/config_schema.json b/src/go/collectors/go.d.plugin/modules/hddtemp/config_schema.json new file mode 100644 index 0000000000..2858fbe026 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/hddtemp/config_schema.json @@ -0,0 +1,44 @@ +{ + "jsonSchema": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "HddTemp collector configuration.", + "type": "object", + "properties": { + "update_every": { + "title": "Update every", + "description": "Data collection interval, measured in seconds.", + "type": "integer", + "minimum": 1, + "default": 1 + }, + "address": { + "title": "Address", + "description": "The IP address and port where the hddtemp daemon listens for connections.", + "type": "string", + "default": "127.0.0.1:7634" + }, + "timeout": { + "title": "Timeout", + "description": "Timeout for establishing a connection and communication (reading and writing) in seconds.", + "type": "number", + "minimum": 0.5, + "default": 1 + } + }, + "required": [ + "address" + ], + "additionalProperties": false, + "patternProperties": { + "^name$": {} + } + }, + "uiSchema": { + "uiOptions": { + "fullPage": true + }, + "timeout": { + "ui:help": "Accepts decimals for precise control (e.g., type 1.5 for 1.5 seconds)." + } + } +} diff --git a/src/go/collectors/go.d.plugin/modules/hddtemp/hddtemp.go b/src/go/collectors/go.d.plugin/modules/hddtemp/hddtemp.go new file mode 100644 index 0000000000..3976506053 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/hddtemp/hddtemp.go @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package hddtemp + +import ( + _ "embed" + "errors" + "time" + + "github.com/netdata/netdata/go/go.d.plugin/agent/module" + "github.com/netdata/netdata/go/go.d.plugin/pkg/web" +) + +//go:embed "config_schema.json" +var configSchema string + +func init() { + module.Register("hddtemp", module.Creator{ + JobConfigSchema: configSchema, + Create: func() module.Module { return New() }, + }) +} + +func New() *HddTemp { + return &HddTemp{ + Config: Config{ + Address: "127.0.0.1:7634", + Timeout: web.Duration(time.Second * 1), + }, + newHddTempConn: newHddTempConn, + charts: &module.Charts{}, + disks: make(map[string]bool), + disksTemp: make(map[string]bool), + } +} + +type Config struct { + UpdateEvery int `yaml:"update_every" json:"update_every"` + Address string `yaml:"address" json:"address"` + Timeout web.Duration `yaml:"timeout" json:"timeout"` +} + +type ( + HddTemp struct { + module.Base + Config `yaml:",inline" json:""` + + charts *module.Charts + + newHddTempConn func(Config) hddtempConn + + disks map[string]bool + disksTemp map[string]bool + } + + hddtempConn interface { + connect() error + disconnect() + queryHddTemp() (string, error) + } +) + +func (h *HddTemp) Configuration() any { + return h.Config +} + +func (h *HddTemp) Init() error { + if h.Address == "" { + h.Error("config: 'address' not set") + return errors.New("address not set") + } + + return nil +} + +func (h *HddTemp) Check() error { + mx, err := h.collect() + if err != nil { + h.Error(err) + return err + } + if len(mx) == 0 { + return errors.New("no metrics collected") + } + return nil +} + +func (h *HddTemp) Charts() *module.Charts { + return h.charts +} + +func (h *HddTemp) Collect() map[string]int64 { + mx, err := h.collect() + if err != nil { + h.Error(err) + } + + if len(mx) == 0 { + return nil + } + return mx +} + +func (h *HddTemp) Cleanup() {} diff --git a/src/go/collectors/go.d.plugin/modules/hddtemp/hddtemp_test.go b/src/go/collectors/go.d.plugin/modules/hddtemp/hddtemp_test.go new file mode 100644 index 0000000000..cab4ceb970 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/hddtemp/hddtemp_test.go @@ -0,0 +1,321 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package hddtemp + +import ( + "errors" + "os" + "testing" + + "github.com/netdata/netdata/go/go.d.plugin/agent/module" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var ( + dataConfigJSON, _ = os.ReadFile("testdata/config.json") + dataConfigYAML, _ = os.ReadFile("testdata/config.yaml") + + dataAllOK, _ = os.ReadFile("testdata/hddtemp-all-ok.txt") + dataAllSleep, _ = os.ReadFile("testdata/hddtemp-all-sleep.txt") +) + +func Test_testDataIsValid(t *testing.T) { + for name, data := range map[string][]byte{ + "dataConfigJSON": dataConfigJSON, + "dataConfigYAML": dataConfigYAML, + + "dataAllOK": dataAllOK, + "dataAllSleep": dataAllSleep, + } { + require.NotNil(t, data, name) + } +} + +func TestHddTemp_ConfigurationSerialize(t *testing.T) { + module.TestConfigurationSerialize(t, &HddTemp{}, dataConfigJSON, dataConfigYAML) +} + +func TestHddTemp_Init(t *testing.T) { + tests := map[string]struct { + config Config + wantFail bool + }{ + "success with default config": { + wantFail: false, + config: New().Config, + }, + "fails if address not set": { + wantFail: true, + config: func() Config { + conf := New().Config + conf.Address = "" + return conf + }(), + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + hdd := New() + hdd.Config = test.config + + if test.wantFail { + assert.Error(t, hdd.Init()) + } else { + assert.NoError(t, hdd.Init()) + } + }) + } +} + +func TestHddTemp_Cleanup(t *testing.T) { + tests := map[string]struct { + prepare func() *HddTemp + }{ + "not initialized": { + prepare: func() *HddTemp { + return New() + }, + }, + "after check": { + prepare: func() *HddTemp { + hdd := New() + hdd.newHddTempConn = func(config Config) hddtempConn { return prepareMockAllDisksOk() } + _ = hdd.Check() + return hdd + }, + }, + "after collect": { + prepare: func() *HddTemp { + hdd := New() + hdd.newHddTempConn = func(config Config) hddtempConn { return prepareMockAllDisksOk() } + _ = hdd.Collect() + return hdd + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + hdd := test.prepare() + + assert.NotPanics(t, hdd.Cleanup) + }) + } +} + +func TestHddTemp_Charts(t *testing.T) { + assert.NotNil(t, New().Charts()) +} + +func TestHddTemp_Check(t *testing.T) { + tests := map[string]struct { + prepareMock func() *mockHddTempConn + wantFail bool + }{ + "all disks ok": { + wantFail: false, + prepareMock: prepareMockAllDisksOk, + }, + "all disks sleep": { + wantFail: false, + prepareMock: prepareMockAllDisksSleep, + }, + "err on connect": { + wantFail: true, + prepareMock: prepareMockErrOnConnect, + }, + "unexpected response": { + wantFail: true, + prepareMock: prepareMockUnexpectedResponse, + }, + "empty response": { + wantFail: true, + prepareMock: prepareMockEmptyResponse, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + hdd := New() + mock := test.prepareMock() + hdd.newHddTempConn = func(config Config) hddtempConn { return mock } + + if test.wantFail { + assert.Error(t, hdd.Check()) + } else { + assert.NoError(t, hdd.Check()) + } + }) + } +} + +func TestHddTemp_Collect(t *testing.T) { + tests := map[string]struct { + prepareMock func() *mockHddTempConn + wantMetrics map[string]int64 + wantDisconnect bool + wantCharts int + }{ + "all disks ok": { + prepareMock: prepareMockAllDisksOk, + wantDisconnect: true, + wantCharts: 2 * 4, + wantMetrics: map[string]int64{ + "disk_sda_temp_sensor_status_err": 0, + "disk_sda_temp_sensor_status_na": 0, + "disk_sda_temp_sensor_status_nos": 0, + "disk_sda_temp_sensor_status_ok": 1, + "disk_sda_temp_sensor_status_slp": 0, + "disk_sda_temp_sensor_status_unk": 0, + "disk_sda_temperature": 50, + "disk_sdb_temp_sensor_status_err": 0, + "disk_sdb_temp_sensor_status_na": 0, + "disk_sdb_temp_sensor_status_nos": 0, + "disk_sdb_temp_sensor_status_ok": 1, + "disk_sdb_temp_sensor_status_slp": 0, + "disk_sdb_temp_sensor_status_unk": 0, + "disk_sdb_temperature": 49, + "disk_sdc_temp_sensor_status_err": 0, + "disk_sdc_temp_sensor_status_na": 0, + "disk_sdc_temp_sensor_status_nos": 0, + "disk_sdc_temp_sensor_status_ok": 1, + "disk_sdc_temp_sensor_status_slp": 0, + "disk_sdc_temp_sensor_status_unk": 0, + "disk_sdc_temperature": 27, + "disk_sdd_temp_sensor_status_err": 0, + "disk_sdd_temp_sensor_status_na": 0, + "disk_sdd_temp_sensor_status_nos": 0, + "disk_sdd_temp_sensor_status_ok": 1, + "disk_sdd_temp_sensor_status_slp": 0, + "disk_sdd_temp_sensor_status_unk": 0, + "disk_sdd_temperature": 29, + }, + }, + "all disks sleep": { + prepareMock: prepareMockAllDisksSleep, + wantDisconnect: true, + wantCharts: 3, + wantMetrics: map[string]int64{ + "disk_ata-HUP722020APA330_BFGWU7WF_temp_sensor_status_err": 0, + "disk_ata-HUP722020APA330_BFGWU7WF_temp_sensor_status_na": 0, + "disk_ata-HUP722020APA330_BFGWU7WF_temp_sensor_status_nos": 0, + "disk_ata-HUP722020APA330_BFGWU7WF_temp_sensor_status_ok": 0, + "disk_ata-HUP722020APA330_BFGWU7WF_temp_sensor_status_slp": 1, + "disk_ata-HUP722020APA330_BFGWU7WF_temp_sensor_status_unk": 0, + "disk_ata-HUP722020APA330_BFJ0WS3F_temp_sensor_status_err": 0, + "disk_ata-HUP722020APA330_BFJ0WS3F_temp_sensor_status_na": 0, + "disk_ata-HUP722020APA330_BFJ0WS3F_temp_sensor_status_nos": 0, + "disk_ata-HUP722020APA330_BFJ0WS3F_temp_sensor_status_ok": 0, + "disk_ata-HUP722020APA330_BFJ0WS3F_temp_sensor_status_slp": 1, + "disk_ata-HUP722020APA330_BFJ0WS3F_temp_sensor_status_unk": 0, + "disk_ata-WDC_WD10EARS-00Y5B1_WD-WCAV5R693922_temp_sensor_status_err": 0, + "disk_ata-WDC_WD10EARS-00Y5B1_WD-WCAV5R693922_temp_sensor_status_na": 0, + "disk_ata-WDC_WD10EARS-00Y5B1_WD-WCAV5R693922_temp_sensor_status_nos": 0, + "disk_ata-WDC_WD10EARS-00Y5B1_WD-WCAV5R693922_temp_sensor_status_ok": 0, + "disk_ata-WDC_WD10EARS-00Y5B1_WD-WCAV5R693922_temp_sensor_status_slp": 1, + "disk_ata-WDC_WD10EARS-00Y5B1_WD-WCAV5R693922_temp_sensor_status_unk": 0, + }, + }, + "err on connect": { + prepareMock: prepareMockErrOnConnect, + wantDisconnect: false, + }, + "unexpected response": { + prepareMock: prepareMockUnexpectedResponse, + wantDisconnect: true, + }, + "empty response": { + prepareMock: prepareMockEmptyResponse, + wantDisconnect: true, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + hdd := New() + mock := test.prepareMock() + hdd.newHddTempConn = func(config Config) hddtempConn { return mock } + + mx := hdd.Collect() + + assert.Equal(t, test.wantMetrics, mx) + assert.Len(t, *hdd.Charts(), test.wantCharts) + assert.Equal(t, test.wantDisconnect, mock.disconnectCalled) + testMetricsHasAllChartsDims(t, hdd, mx) + }) + } +} + +func testMetricsHasAllChartsDims(t *testing.T, hdd *HddTemp, mx map[string]int64) { + for _, chart := range *hdd.Charts() { + if chart.Obsolete { + continue + } + for _, dim := range chart.Dims { + _, ok := mx[dim.ID] + assert.Truef(t, ok, "collected metrics has no data for dim '%s' chart '%s'", dim.ID, chart.ID) + } + for _, v := range chart.Vars { + _, ok := mx[v.ID] + assert.Truef(t, ok, "collected metrics has no data for var '%s' chart '%s'", v.ID, chart.ID) + } + } +} + +func prepareMockAllDisksOk() *mockHddTempConn { + return &mockHddTempConn{ + hddTempLine: string(dataAllOK), + } +} + +func prepareMockAllDisksSleep() *mockHddTempConn { + return &mockHddTempConn{ + hddTempLine: string(dataAllSleep), + } +} + +func prepareMockErrOnConnect() *mockHddTempConn { + return &mockHddTempConn{ + errOnConnect: true, + } +} + +func prepareMockUnexpectedResponse() *mockHddTempConn { + return &mockHddTempConn{ + hddTempLine: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", + } +} + +func prepareMockEmptyResponse() *mockHddTempConn { + return &mockHddTempConn{ + hddTempLine: "", + } +} + +type mockHddTempConn struct { + errOnConnect bool + errOnQueryHddTemp bool + hddTempLine string + disconnectCalled bool +} + +func (m *mockHddTempConn) connect() error { + if m.errOnConnect { + return errors.New("mock.connect() error") + } + return nil +} + +func (m *mockHddTempConn) disconnect() { + m.disconnectCalled = true +} + +func (m *mockHddTempConn) queryHddTemp() (string, error) { + if m.errOnQueryHddTemp { + return "", errors.New("mock.queryHddTemp() error") + } + return m.hddTempLine, nil +} diff --git a/src/go/collectors/go.d.plugin/modules/hddtemp/metadata.yaml b/src/go/collectors/go.d.plugin/modules/hddtemp/metadata.yaml new file mode 100644 index 0000000000..74206ebc95 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/hddtemp/metadata.yaml @@ -0,0 +1,134 @@ +plugin_name: go.d.plugin +modules: + - meta: + id: collector-go.d.plugin-hddtemp + plugin_name: go.d.plugin + module_name: hddtemp + monitored_instance: + name: HDD temperature + link: https://linux.die.net/man/8/hddtemp + categories: + - data-collection.hardware-devices-and-sensors + icon_filename: "hard-drive.svg" + related_resources: + integrations: + list: [] + info_provided_to_referring_integrations: + description: "" + keywords: + - hardware + - hdd temperature + - disk temperature + - temperature + most_popular: false + overview: + data_collection: + metrics_description: | + This collector monitors disk temperatures. + method_description: | + It retrieves temperature data for attached disks by querying the hddtemp daemon at regular intervals. + supported_platforms: + include: + - Linux + exclude: [] + multi_instance: true + additional_permissions: + description: "" + default_behavior: + auto_detection: + description: By default, this collector will attempt to connect to the `hddtemp` daemon on `127.0.0.1:7634` + limits: + description: "" + performance_impact: + description: "" + setup: + prerequisites: + list: + - title: Install hddtemp + description: | + Install `hddtemp` using your distribution's package manager. + configuration: + file: + name: go.d/hddtemp.conf + options: + description: | + The following options can be defined globally: update_every, autodetection_retry. + folding: + title: Config options + enabled: true + list: + - name: update_every + description: Data collection frequency. + default_value: 1 + required: false + - name: autodetection_retry + description: Recheck interval in seconds. Zero means no recheck will be scheduled. + default_value: 0 + required: false + - name: address + description: The IP address and port where the hddtemp daemon listens for connections. + default_value: 127.0.0.1:7634 + required: true + - name: timeout + description: Connection, read, and write timeout duration in seconds. The timeout includes name resolution. + default_value: 1 + required: false + examples: + folding: + title: Config + enabled: true + list: + - name: Basic + description: A basic example configuration. + config: | + jobs: + - name: local + address: 127.0.0.1:7634 + - name: Multi-instance + description: | + > **Note**: When you define multiple jobs, their names must be unique. + + Collecting metrics from local and remote instances. + config: | + jobs: + - name: local + address: 127.0.0.1:7634 + + - name: remote + address: 203.0.113.0:7634 + troubleshooting: + problems: + list: [] + alerts: [] + metrics: + folding: + title: Metrics + enabled: false + description: "" + availability: [] + scopes: + - name: disk + description: These metrics refer to the Disk. + labels: + - name: disk_id + description: Disk identifier. It is derived from the device path (e.g. sda or ata-HUP722020APA330_BFJ0WS3F) + - name: model + description: Disk model + metrics: + - name: hddtemp.disk_temperature + description: Disk temperature + unit: Celsius + chart_type: line + dimensions: + - name: temperature + - name: hddtemp.disk_temperature_sensor_status + description: Disk temperature sensor status + unit: status + chart_type: line + dimensions: + - name: ok + - name: err + - name: na + - name: unk + - name: nos + - name: slp diff --git a/src/go/collectors/go.d.plugin/modules/hddtemp/testdata/config.json b/src/go/collectors/go.d.plugin/modules/hddtemp/testdata/config.json new file mode 100644 index 0000000000..e868347203 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/hddtemp/testdata/config.json @@ -0,0 +1,5 @@ +{ + "update_every": 123, + "address": "ok", + "timeout": 123.123 +} diff --git a/src/go/collectors/go.d.plugin/modules/hddtemp/testdata/config.yaml b/src/go/collectors/go.d.plugin/modules/hddtemp/testdata/config.yaml new file mode 100644 index 0000000000..1b81d09eb8 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/hddtemp/testdata/config.yaml @@ -0,0 +1,3 @@ +update_every: 123 +address: "ok" +timeout: 123.123 diff --git a/src/go/collectors/go.d.plugin/modules/hddtemp/testdata/hddtemp-all-ok.txt b/src/go/collectors/go.d.plugin/modules/hddtemp/testdata/hddtemp-all-ok.txt new file mode 100644 index 0000000000..5f6606e812 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/hddtemp/testdata/hddtemp-all-ok.txt @@ -0,0 +1 @@ +|/dev/sda|WDC WD181KRYZ-01AGBB0|122|F||/dev/sdb|WDC WD181KRYZ-01AGBB0|49|C||/dev/sdc|WDC WDS400T1R0A-68A4W0|27|C||/dev/sdd|WDC WDS400T1R0A-68A4W0|29|C|
\ No newline at end of file diff --git a/src/go/collectors/go.d.plugin/modules/hddtemp/testdata/hddtemp-all-sleep.txt b/src/go/collectors/go.d.plugin/modules/hddtemp/testdata/hddtemp-all-sleep.txt new file mode 100644 index 0000000000..732b62c762 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/hddtemp/testdata/hddtemp-all-sleep.txt @@ -0,0 +1 @@ +|/dev/disk/by-id/ata-HUP722020APA330_BFJ0WS3F|HUP722020APA330|SLP|*||/dev/disk/by-id/ata-HUP722020APA330_BFGWU7WF|HUP722020APA330|SLP|*||/dev/di |