From e284f1502b7b3b515c53d00582292eed8fe6b49b Mon Sep 17 00:00:00 2001 From: George MacRorie Date: Fri, 5 Jul 2019 17:28:45 +0100 Subject: [PATCH 01/14] Check for Media and Data Integrity Errors metric from smart plugin --- plugins/inputs/smart/smart_test.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/plugins/inputs/smart/smart_test.go b/plugins/inputs/smart/smart_test.go index c801c7a6161b7..bc288fc749dd3 100644 --- a/plugins/inputs/smart/smart_test.go +++ b/plugins/inputs/smart/smart_test.go @@ -484,6 +484,17 @@ func TestGatherNvme(t *testing.T) { }, time.Now(), ), + testutil.MustMetric("smart_attribute", + map[string]string{ + "device": ".", + "name": "Media_and_Data_Integrity_Errors", + "serial_no": "D704940282?", + }, + map[string]interface{}{ + "raw_value": 0, + }, + time.Now(), + ), testutil.MustMetric("smart_attribute", map[string]string{ "device": ".", From 6b2275bdbacce27aae124caad8e9e0f80f428966 Mon Sep 17 00:00:00 2001 From: George MacRorie Date: Sat, 6 Jul 2019 14:49:18 +0100 Subject: [PATCH 02/14] Collect Media and Data Integrity Errors attributes via smart input plugin --- plugins/inputs/smart/smart.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/plugins/inputs/smart/smart.go b/plugins/inputs/smart/smart.go index 93d4a0076ee06..ad89feb3afef3 100644 --- a/plugins/inputs/smart/smart.go +++ b/plugins/inputs/smart/smart.go @@ -48,6 +48,8 @@ var ( nvmePowerCycleAttr = regexp.MustCompile("^Power Cycles:\\s+(.*)$") // Power On Hours: 6,038 nvmePowerOnAttr = regexp.MustCompile("^Power On Hours:\\s+(.*)$") + // Media and Data Integrity Errors: 0 + nvmeIntegrityErrAttr = regexp.MustCompile("^Media and Data Integrity Errors:\\s+(.*)$") // ID# ATTRIBUTE_NAME FLAGS VALUE WORST THRESH FAIL RAW_VALUE // 1 Raw_Read_Error_Rate -O-RC- 200 200 000 - 0 @@ -339,6 +341,18 @@ func gatherDisk(acc telegraf.Accumulator, usesudo, collectAttributes bool, smart continue } + if errors := nvmeIntegrityErrAttr.FindStringSubmatch(line); len(errors) > 1 { + tags["name"] = "Media_and_Data_Integrity_Errors" + i, err := strconv.ParseInt(strings.Replace(errors[1], ",", "", -1), 10, 64) + if err != nil { + continue + } + fields["raw_value"] = i + + acc.AddFields("smart_attribute", fields, tags) + continue + } + if loadCycle := sasLoadCycleAttr.FindStringSubmatch(line); len(loadCycle) > 1 { tags["id"] = "193" tags["name"] = "Load_Cycle_Count" From 13f01e11f8b1d8bbc49beab0f18b7c87eecada37 Mon Sep 17 00:00:00 2001 From: George MacRorie Date: Sat, 6 Jul 2019 14:50:22 +0100 Subject: [PATCH 03/14] Ignore vim swap files via gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 4176a04131cfc..0a49bfa765ed8 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ /telegraf.exe /telegraf.gz /vendor +*.swp +*.swo From 0c19c5fc5c649e6550cd7b18bd5d2b4db5eec246 Mon Sep 17 00:00:00 2001 From: George MacRorie Date: Sat, 6 Jul 2019 14:52:38 +0100 Subject: [PATCH 04/14] Add failing check to smart input plugin for Error_Information_Log_Entries collection --- plugins/inputs/smart/smart_test.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/plugins/inputs/smart/smart_test.go b/plugins/inputs/smart/smart_test.go index bc288fc749dd3..628fade75f8cd 100644 --- a/plugins/inputs/smart/smart_test.go +++ b/plugins/inputs/smart/smart_test.go @@ -495,6 +495,17 @@ func TestGatherNvme(t *testing.T) { }, time.Now(), ), + testutil.MustMetric("smart_attribute", + map[string]string{ + "device": ".", + "name": "Error_Information_Log_Entries", + "serial_no": "D704940282?", + }, + map[string]interface{}{ + "raw_value": 119699, + }, + time.Now(), + ), testutil.MustMetric("smart_attribute", map[string]string{ "device": ".", From 18889e4dc58f3955916e5b3a109bd8fe20c6cc00 Mon Sep 17 00:00:00 2001 From: George MacRorie Date: Sat, 6 Jul 2019 14:57:01 +0100 Subject: [PATCH 05/14] Collect Error Information Log Entries attributes via smart input plugin --- plugins/inputs/smart/smart.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/plugins/inputs/smart/smart.go b/plugins/inputs/smart/smart.go index ad89feb3afef3..ae523d6e0f0a6 100644 --- a/plugins/inputs/smart/smart.go +++ b/plugins/inputs/smart/smart.go @@ -50,6 +50,8 @@ var ( nvmePowerOnAttr = regexp.MustCompile("^Power On Hours:\\s+(.*)$") // Media and Data Integrity Errors: 0 nvmeIntegrityErrAttr = regexp.MustCompile("^Media and Data Integrity Errors:\\s+(.*)$") + // Error Information Log Entries: 119699 + nvmeErrorLogAttr = regexp.MustCompile("^Error Information Log Entries:\\s+(.*)$") // ID# ATTRIBUTE_NAME FLAGS VALUE WORST THRESH FAIL RAW_VALUE // 1 Raw_Read_Error_Rate -O-RC- 200 200 000 - 0 @@ -353,6 +355,18 @@ func gatherDisk(acc telegraf.Accumulator, usesudo, collectAttributes bool, smart continue } + if entries := nvmeErrorLogAttr.FindStringSubmatch(line); len(entries) > 1 { + tags["name"] = "Error_Information_Log_Entries" + i, err := strconv.ParseInt(strings.Replace(entries[1], ",", "", -1), 10, 64) + if err != nil { + continue + } + fields["raw_value"] = i + + acc.AddFields("smart_attribute", fields, tags) + continue + } + if loadCycle := sasLoadCycleAttr.FindStringSubmatch(line); len(loadCycle) > 1 { tags["id"] = "193" tags["name"] = "Load_Cycle_Count" From 4eb885762b5b41938aa6140966ca5c835eafe2f9 Mon Sep 17 00:00:00 2001 From: George MacRorie Date: Sat, 6 Jul 2019 15:13:43 +0100 Subject: [PATCH 06/14] Add failing check to smart input plugin for Available_Spare attr collection --- plugins/inputs/smart/smart_test.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/plugins/inputs/smart/smart_test.go b/plugins/inputs/smart/smart_test.go index 628fade75f8cd..89e6b62fc064e 100644 --- a/plugins/inputs/smart/smart_test.go +++ b/plugins/inputs/smart/smart_test.go @@ -506,6 +506,17 @@ func TestGatherNvme(t *testing.T) { }, time.Now(), ), + testutil.MustMetric("smart_attribute", + map[string]string{ + "device": ".", + "name": "Available_Spare", + "serial_no": "D704940282?", + }, + map[string]interface{}{ + "raw_value": 100, + }, + time.Now(), + ), testutil.MustMetric("smart_attribute", map[string]string{ "device": ".", From e43369957d5fafdeabd1d26c29c7ce1805b23b01 Mon Sep 17 00:00:00 2001 From: George MacRorie Date: Sat, 6 Jul 2019 15:16:58 +0100 Subject: [PATCH 07/14] Collect Available Spare attribute in smart input plugin --- plugins/inputs/smart/smart.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/plugins/inputs/smart/smart.go b/plugins/inputs/smart/smart.go index ae523d6e0f0a6..010da94bbc3b2 100644 --- a/plugins/inputs/smart/smart.go +++ b/plugins/inputs/smart/smart.go @@ -52,6 +52,8 @@ var ( nvmeIntegrityErrAttr = regexp.MustCompile("^Media and Data Integrity Errors:\\s+(.*)$") // Error Information Log Entries: 119699 nvmeErrorLogAttr = regexp.MustCompile("^Error Information Log Entries:\\s+(.*)$") + // Available Spare: 100% + nvmeAvailableSpareAttr = regexp.MustCompile("^Available Spare:\\s+(.*)$") // ID# ATTRIBUTE_NAME FLAGS VALUE WORST THRESH FAIL RAW_VALUE // 1 Raw_Read_Error_Rate -O-RC- 200 200 000 - 0 @@ -367,6 +369,18 @@ func gatherDisk(acc telegraf.Accumulator, usesudo, collectAttributes bool, smart continue } + if spare := nvmeAvailableSpareAttr.FindStringSubmatch(line); len(spare) > 1 { + tags["name"] = "Available_Spare" + i, err := strconv.ParseInt(strings.Replace(spare[1], "%", "", -1), 10, 64) + if err != nil { + continue + } + fields["raw_value"] = i + + acc.AddFields("smart_attribute", fields, tags) + continue + } + if loadCycle := sasLoadCycleAttr.FindStringSubmatch(line); len(loadCycle) > 1 { tags["id"] = "193" tags["name"] = "Load_Cycle_Count" From 4762b756fd07ba126123cedeefdfb1600d7efb68 Mon Sep 17 00:00:00 2001 From: George MacRorie Date: Mon, 8 Jul 2019 14:28:12 +0100 Subject: [PATCH 08/14] Refactor smart input plugin nvme/sas collection to be more extensible --- plugins/inputs/smart/smart.go | 220 ++++++++++++++-------------------- 1 file changed, 91 insertions(+), 129 deletions(-) diff --git a/plugins/inputs/smart/smart.go b/plugins/inputs/smart/smart.go index 010da94bbc3b2..de6ab6bcde1b6 100644 --- a/plugins/inputs/smart/smart.go +++ b/plugins/inputs/smart/smart.go @@ -36,24 +36,8 @@ var ( // PASSED, FAILED, UNKNOWN smartOverallHealth = regexp.MustCompile("^(SMART overall-health self-assessment test result|SMART Health Status):\\s+(\\w+).*$") - // Accumulated start-stop cycles: 7 - sasStartStopAttr = regexp.MustCompile("^Accumulated start-stop cycles:\\s+(.*)$") - // Accumulated load-unload cycles: 39 - sasLoadCycleAttr = regexp.MustCompile("^Accumulated load-unload cycles:\\s+(.*)$") - // Current Drive Temperature: 34 C - sasTempAttr = regexp.MustCompile("^Current Drive Temperature:\\s+(.*)\\s+C(.*)$") - // Temperature: 38 Celsius - nvmeTempAttr = regexp.MustCompile("^Temperature:\\s+(.*)\\s+(.*)$") - // Power Cycles: 472 - nvmePowerCycleAttr = regexp.MustCompile("^Power Cycles:\\s+(.*)$") - // Power On Hours: 6,038 - nvmePowerOnAttr = regexp.MustCompile("^Power On Hours:\\s+(.*)$") - // Media and Data Integrity Errors: 0 - nvmeIntegrityErrAttr = regexp.MustCompile("^Media and Data Integrity Errors:\\s+(.*)$") - // Error Information Log Entries: 119699 - nvmeErrorLogAttr = regexp.MustCompile("^Error Information Log Entries:\\s+(.*)$") - // Available Spare: 100% - nvmeAvailableSpareAttr = regexp.MustCompile("^Available Spare:\\s+(.*)$") + // sasNvmeAttr is a SAS or NVME SMART attribute + sasNvmeAttr = regexp.MustCompile(`^([^:]*):\s+(.*)$`) // ID# ATTRIBUTE_NAME FLAGS VALUE WORST THRESH FAIL RAW_VALUE // 1 Raw_Read_Error_Rate -O-RC- 200 200 000 - 0 @@ -68,6 +52,55 @@ var ( "194": "temp_c", "199": "udma_crc_errors", } + + sasNvmeAttributes = map[string]struct { + ID string + Name string + Parse func(fields, deviceFields map[string]interface{}, str string) error + }{ + "Accumulated start-stop cycles": { + ID: "4", + Name: "Start_Stop_Count", + }, + "Accumulated load-unload cycles": { + ID: "193", + Name: "Load_Cycle_Count", + }, + "Current Drive Temperature": { + ID: "194", + Name: "Temperature_Celsius", + Parse: parseTemperature, + }, + "Temperature": { + ID: "194", + Name: "Temperature_Celsius", + Parse: parseTemperature, + }, + "Power Cycles": { + ID: "12", + Name: "Power_Cycle_Count", + }, + "Power On Hours": { + ID: "9", + Name: "Power_On_Hours", + }, + "Media and Data Integrity Errors": { + Name: "Media_and_Data_Integrity_Errors", + }, + "Error Information Log Entries": { + Name: "Error_Information_Log_Entries", + }, + "Available Spare": { + Name: "Available_Spare", + Parse: func(fields, deviceFields map[string]interface{}, str string) error { + if str[len(str)-1] == '%' { + str = str[:len(str)-1] + } + + return parseCommaSeperatedInt(fields, deviceFields, str) + }, + }, + } ) type Smart struct { @@ -306,118 +339,24 @@ func gatherDisk(acc telegraf.Accumulator, usesudo, collectAttributes bool, smart } } else { if collectAttributes { - if startStop := sasStartStopAttr.FindStringSubmatch(line); len(startStop) > 1 { - tags["id"] = "4" - tags["name"] = "Start_Stop_Count" - i, err := strconv.ParseInt(strings.Replace(startStop[1], ",", "", -1), 10, 64) - if err != nil { - continue - } - fields["raw_value"] = i - - acc.AddFields("smart_attribute", fields, tags) - continue - } - - if powerCycle := nvmePowerCycleAttr.FindStringSubmatch(line); len(powerCycle) > 1 { - tags["id"] = "12" - tags["name"] = "Power_Cycle_Count" - i, err := strconv.ParseInt(strings.Replace(powerCycle[1], ",", "", -1), 10, 64) - if err != nil { - continue - } - fields["raw_value"] = i - - acc.AddFields("smart_attribute", fields, tags) - continue - } - - if powerOn := nvmePowerOnAttr.FindStringSubmatch(line); len(powerOn) > 1 { - tags["id"] = "9" - tags["name"] = "Power_On_Hours" - i, err := strconv.ParseInt(strings.Replace(powerOn[1], ",", "", -1), 10, 64) - if err != nil { - continue - } - fields["raw_value"] = i - - acc.AddFields("smart_attribute", fields, tags) - continue - } - - if errors := nvmeIntegrityErrAttr.FindStringSubmatch(line); len(errors) > 1 { - tags["name"] = "Media_and_Data_Integrity_Errors" - i, err := strconv.ParseInt(strings.Replace(errors[1], ",", "", -1), 10, 64) - if err != nil { - continue - } - fields["raw_value"] = i - - acc.AddFields("smart_attribute", fields, tags) - continue - } - - if entries := nvmeErrorLogAttr.FindStringSubmatch(line); len(entries) > 1 { - tags["name"] = "Error_Information_Log_Entries" - i, err := strconv.ParseInt(strings.Replace(entries[1], ",", "", -1), 10, 64) - if err != nil { - continue - } - fields["raw_value"] = i - - acc.AddFields("smart_attribute", fields, tags) - continue - } - - if spare := nvmeAvailableSpareAttr.FindStringSubmatch(line); len(spare) > 1 { - tags["name"] = "Available_Spare" - i, err := strconv.ParseInt(strings.Replace(spare[1], "%", "", -1), 10, 64) - if err != nil { - continue - } - fields["raw_value"] = i - - acc.AddFields("smart_attribute", fields, tags) - continue - } - - if loadCycle := sasLoadCycleAttr.FindStringSubmatch(line); len(loadCycle) > 1 { - tags["id"] = "193" - tags["name"] = "Load_Cycle_Count" - i, err := strconv.ParseInt(strings.Replace(loadCycle[1], ",", "", -1), 10, 64) - if err != nil { - continue + if matches := sasNvmeAttr.FindStringSubmatch(line); len(matches) > 2 { + if attr, ok := sasNvmeAttributes[matches[1]]; ok { + tags["name"] = attr.Name + if attr.ID != "" { + tags["id"] = attr.ID + } + + parse := parseCommaSeperatedInt + if attr.Parse != nil { + parse = attr.Parse + } + + if err := parse(fields, deviceFields, matches[2]); err != nil { + continue + } + + acc.AddFields("smart_attribute", fields, tags) } - fields["raw_value"] = i - - acc.AddFields("smart_attribute", fields, tags) - continue - } - - if temp := sasTempAttr.FindStringSubmatch(line); len(temp) > 1 { - tags["id"] = "194" - tags["name"] = "Temperature_Celsius" - tempC, err := strconv.ParseInt(temp[1], 10, 64) - if err != nil { - continue - } - fields["raw_value"] = tempC - deviceFields["temp_c"] = tempC - - acc.AddFields("smart_attribute", fields, tags) - } - - if temp := nvmeTempAttr.FindStringSubmatch(line); len(temp) > 1 { - tags["id"] = "194" - tags["name"] = "Temperature_Celsius" - tempC, err := strconv.ParseInt(temp[1], 10, 64) - if err != nil { - continue - } - fields["raw_value"] = tempC - deviceFields["temp_c"] = tempC - - acc.AddFields("smart_attribute", fields, tags) } } } @@ -466,6 +405,29 @@ func parseInt(str string) int64 { return 0 } +func parseCommaSeperatedInt(fields, deviceFields map[string]interface{}, str string) error { + i, err := strconv.ParseInt(strings.Replace(str, ",", "", -1), 10, 64) + if err != nil { + return err + } + + fields["raw_value"] = i + + return nil +} + +func parseTemperature(fields, deviceFields map[string]interface{}, str string) error { + var temp int64 + if _, err := fmt.Sscanf(str, "%d C", &temp); err != nil { + return err + } + + fields["raw_value"] = temp + deviceFields["temp_c"] = temp + + return nil +} + func init() { m := Smart{} path, _ := exec.LookPath("smartctl") From ddb5a655b12f42fc6f482dcb39dcde24fffb70e0 Mon Sep 17 00:00:00 2001 From: George MacRorie Date: Mon, 8 Jul 2019 15:07:53 +0100 Subject: [PATCH 09/14] Replace unused input argument with _ in smart input plugin --- plugins/inputs/smart/smart.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/inputs/smart/smart.go b/plugins/inputs/smart/smart.go index de6ab6bcde1b6..0ad0960d89da7 100644 --- a/plugins/inputs/smart/smart.go +++ b/plugins/inputs/smart/smart.go @@ -405,7 +405,7 @@ func parseInt(str string) int64 { return 0 } -func parseCommaSeperatedInt(fields, deviceFields map[string]interface{}, str string) error { +func parseCommaSeperatedInt(fields, _ map[string]interface{}, str string) error { i, err := strconv.ParseInt(strings.Replace(str, ",", "", -1), 10, 64) if err != nil { return err From 65488fb7d8982fc97737b559a1fd5c243c1b9240 Mon Sep 17 00:00:00 2001 From: George MacRorie Date: Tue, 9 Jul 2019 10:04:39 +0100 Subject: [PATCH 10/14] Remove editor specific files from gitignore (.swo, .swp) --- .gitignore | 2 -- 1 file changed, 2 deletions(-) diff --git a/.gitignore b/.gitignore index 0a49bfa765ed8..4176a04131cfc 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,3 @@ /telegraf.exe /telegraf.gz /vendor -*.swp -*.swo From 2d277f4cb1e06ce09f20eff04cb954229c5bfc46 Mon Sep 17 00:00:00 2001 From: George MacRorie Date: Tue, 9 Jul 2019 10:08:16 +0100 Subject: [PATCH 11/14] Use strings.TrimSuffix instead of reslicing string in smart input plugin --- plugins/inputs/smart/smart.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/plugins/inputs/smart/smart.go b/plugins/inputs/smart/smart.go index 0ad0960d89da7..ec9b71f7d5a78 100644 --- a/plugins/inputs/smart/smart.go +++ b/plugins/inputs/smart/smart.go @@ -37,7 +37,7 @@ var ( smartOverallHealth = regexp.MustCompile("^(SMART overall-health self-assessment test result|SMART Health Status):\\s+(\\w+).*$") // sasNvmeAttr is a SAS or NVME SMART attribute - sasNvmeAttr = regexp.MustCompile(`^([^:]*):\s+(.*)$`) + sasNvmeAttr = regexp.MustCompile(`^([^:]+):\s+(.+)$`) // ID# ATTRIBUTE_NAME FLAGS VALUE WORST THRESH FAIL RAW_VALUE // 1 Raw_Read_Error_Rate -O-RC- 200 200 000 - 0 @@ -93,11 +93,7 @@ var ( "Available Spare": { Name: "Available_Spare", Parse: func(fields, deviceFields map[string]interface{}, str string) error { - if str[len(str)-1] == '%' { - str = str[:len(str)-1] - } - - return parseCommaSeperatedInt(fields, deviceFields, str) + return parseCommaSeperatedInt(fields, deviceFields, strings.TrimSuffix(str, "%")) }, }, } From a8001265a3de7f3e12affbeb84b573e39401c448 Mon Sep 17 00:00:00 2001 From: George MacRorie Date: Tue, 9 Jul 2019 11:07:58 +0100 Subject: [PATCH 12/14] Add failing case around smart input plugin nvme critical warning flags --- plugins/inputs/smart/smart_test.go | 57 +++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/plugins/inputs/smart/smart_test.go b/plugins/inputs/smart/smart_test.go index 89e6b62fc064e..1720d80181709 100644 --- a/plugins/inputs/smart/smart_test.go +++ b/plugins/inputs/smart/smart_test.go @@ -529,6 +529,61 @@ func TestGatherNvme(t *testing.T) { }, time.Now(), ), + testutil.MustMetric("smart_attribute", + map[string]string{ + "device": ".", + "name": "Critical_Warning_Spare_Treshold", + "serial_no": "D704940282?", + }, + map[string]interface{}{ + "raw_value": true, + }, + time.Now(), + ), + testutil.MustMetric("smart_attribute", + map[string]string{ + "device": ".", + "name": "Critical_Warning_Temperature_Above_or_Under_Threshold", + "serial_no": "D704940282?", + }, + map[string]interface{}{ + "raw_value": false, + }, + time.Now(), + ), + testutil.MustMetric("smart_attribute", + map[string]string{ + "device": ".", + "name": "Critical_Warning_Reliability_Degraded", + "serial_no": "D704940282?", + }, + map[string]interface{}{ + "raw_value": false, + }, + time.Now(), + ), + testutil.MustMetric("smart_attribute", + map[string]string{ + "device": ".", + "name": "Critical_Warning_Read_Only", + "serial_no": "D704940282?", + }, + map[string]interface{}{ + "raw_value": true, + }, + time.Now(), + ), + testutil.MustMetric("smart_attribute", + map[string]string{ + "device": ".", + "name": "Critical_Warning_Volative_Memory_Backup_Failed", + "serial_no": "D704940282?", + }, + map[string]interface{}{ + "raw_value": false, + }, + time.Now(), + ), } testutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), @@ -967,7 +1022,7 @@ Local Time is: Fri Jun 15 11:41:35 2018 UTC SMART overall-health self-assessment test result: PASSED SMART/Health Information (NVMe Log 0x02, NSID 0xffffffff) -Critical Warning: 0x00 +Critical Warning: 0x09 Temperature: 38 Celsius Available Spare: 100% Available Spare Threshold: 10% From 625fbd202fbb04cdd0dd91a3fcab46be85e4fc2c Mon Sep 17 00:00:00 2001 From: George MacRorie Date: Tue, 9 Jul 2019 11:09:31 +0100 Subject: [PATCH 13/14] Add smart input plugin nvme critical warning fields --- plugins/inputs/smart/smart.go | 39 +++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/plugins/inputs/smart/smart.go b/plugins/inputs/smart/smart.go index ec9b71f7d5a78..9f3f4755cdf53 100644 --- a/plugins/inputs/smart/smart.go +++ b/plugins/inputs/smart/smart.go @@ -18,6 +18,20 @@ import ( "github.com/influxdata/telegraf/plugins/inputs" ) +const ( + // NVME Critical Warnings as per https://nvmexpress.org + // critical warning spare threshold + criticalWarningST uint8 = 1 << iota + // critical warning temperature above or under threshold + criticalWarningTAUT + // critical warning reliability degraded + criticalWarningRD + // critical warning read only + criticalWarningRO + // critical warning volatile backup memory failed + criticalWarningVMBF +) + var ( // Device Model: APPLE SSD SM256E // Product: HUH721212AL5204 @@ -53,6 +67,14 @@ var ( "199": "udma_crc_errors", } + nvmeCriticalWarnings = map[uint8]string{ + criticalWarningST: "Critical_Warning_Spare_Treshold", + criticalWarningTAUT: "Critical_Warning_Temperature_Above_or_Under_Threshold", + criticalWarningRD: "Critical_Warning_Reliability_Degraded", + criticalWarningRO: "Critical_Warning_Read_Only", + criticalWarningVMBF: "Critical_Warning_Volative_Memory_Backup_Failed", + } + sasNvmeAttributes = map[string]struct { ID string Name string @@ -336,6 +358,23 @@ func gatherDisk(acc telegraf.Accumulator, usesudo, collectAttributes bool, smart } else { if collectAttributes { if matches := sasNvmeAttr.FindStringSubmatch(line); len(matches) > 2 { + if matches[1] == "Critical Warning" { + var flags uint8 + if _, err := fmt.Sscanf(matches[2], "0x%x", &flags); err != nil { + continue + } + + for flag, name := range nvmeCriticalWarnings { + tags["name"] = name + + acc.AddFields("smart_attribute", map[string]interface{}{ + "raw_value": flags&flag > 0, + }, tags) + } + + continue + } + if attr, ok := sasNvmeAttributes[matches[1]]; ok { tags["name"] = attr.Name if attr.ID != "" { From 08f23587ed0e6d5f62c30198543c05208f2f84cd Mon Sep 17 00:00:00 2001 From: George MacRorie Date: Fri, 12 Jul 2019 10:51:26 +0100 Subject: [PATCH 14/14] Measure smart input plugin Critical Warning attribute as integer --- plugins/inputs/smart/smart.go | 52 ++++++++---------------------- plugins/inputs/smart/smart_test.go | 48 ++------------------------- 2 files changed, 15 insertions(+), 85 deletions(-) diff --git a/plugins/inputs/smart/smart.go b/plugins/inputs/smart/smart.go index 9f3f4755cdf53..06bf21e107367 100644 --- a/plugins/inputs/smart/smart.go +++ b/plugins/inputs/smart/smart.go @@ -18,20 +18,6 @@ import ( "github.com/influxdata/telegraf/plugins/inputs" ) -const ( - // NVME Critical Warnings as per https://nvmexpress.org - // critical warning spare threshold - criticalWarningST uint8 = 1 << iota - // critical warning temperature above or under threshold - criticalWarningTAUT - // critical warning reliability degraded - criticalWarningRD - // critical warning read only - criticalWarningRO - // critical warning volatile backup memory failed - criticalWarningVMBF -) - var ( // Device Model: APPLE SSD SM256E // Product: HUH721212AL5204 @@ -67,14 +53,6 @@ var ( "199": "udma_crc_errors", } - nvmeCriticalWarnings = map[uint8]string{ - criticalWarningST: "Critical_Warning_Spare_Treshold", - criticalWarningTAUT: "Critical_Warning_Temperature_Above_or_Under_Threshold", - criticalWarningRD: "Critical_Warning_Reliability_Degraded", - criticalWarningRO: "Critical_Warning_Read_Only", - criticalWarningVMBF: "Critical_Warning_Volative_Memory_Backup_Failed", - } - sasNvmeAttributes = map[string]struct { ID string Name string @@ -112,6 +90,19 @@ var ( "Error Information Log Entries": { Name: "Error_Information_Log_Entries", }, + "Critical Warning": { + Name: "Critical_Warning", + Parse: func(fields, _ map[string]interface{}, str string) error { + var value int64 + if _, err := fmt.Sscanf(str, "0x%x", &value); err != nil { + return err + } + + fields["raw_value"] = value + + return nil + }, + }, "Available Spare": { Name: "Available_Spare", Parse: func(fields, deviceFields map[string]interface{}, str string) error { @@ -358,23 +349,6 @@ func gatherDisk(acc telegraf.Accumulator, usesudo, collectAttributes bool, smart } else { if collectAttributes { if matches := sasNvmeAttr.FindStringSubmatch(line); len(matches) > 2 { - if matches[1] == "Critical Warning" { - var flags uint8 - if _, err := fmt.Sscanf(matches[2], "0x%x", &flags); err != nil { - continue - } - - for flag, name := range nvmeCriticalWarnings { - tags["name"] = name - - acc.AddFields("smart_attribute", map[string]interface{}{ - "raw_value": flags&flag > 0, - }, tags) - } - - continue - } - if attr, ok := sasNvmeAttributes[matches[1]]; ok { tags["name"] = attr.Name if attr.ID != "" { diff --git a/plugins/inputs/smart/smart_test.go b/plugins/inputs/smart/smart_test.go index 1720d80181709..b9886bb084f89 100644 --- a/plugins/inputs/smart/smart_test.go +++ b/plugins/inputs/smart/smart_test.go @@ -532,55 +532,11 @@ func TestGatherNvme(t *testing.T) { testutil.MustMetric("smart_attribute", map[string]string{ "device": ".", - "name": "Critical_Warning_Spare_Treshold", + "name": "Critical_Warning", "serial_no": "D704940282?", }, map[string]interface{}{ - "raw_value": true, - }, - time.Now(), - ), - testutil.MustMetric("smart_attribute", - map[string]string{ - "device": ".", - "name": "Critical_Warning_Temperature_Above_or_Under_Threshold", - "serial_no": "D704940282?", - }, - map[string]interface{}{ - "raw_value": false, - }, - time.Now(), - ), - testutil.MustMetric("smart_attribute", - map[string]string{ - "device": ".", - "name": "Critical_Warning_Reliability_Degraded", - "serial_no": "D704940282?", - }, - map[string]interface{}{ - "raw_value": false, - }, - time.Now(), - ), - testutil.MustMetric("smart_attribute", - map[string]string{ - "device": ".", - "name": "Critical_Warning_Read_Only", - "serial_no": "D704940282?", - }, - map[string]interface{}{ - "raw_value": true, - }, - time.Now(), - ), - testutil.MustMetric("smart_attribute", - map[string]string{ - "device": ".", - "name": "Critical_Warning_Volative_Memory_Backup_Failed", - "serial_no": "D704940282?", - }, - map[string]interface{}{ - "raw_value": false, + "raw_value": int64(9), }, time.Now(), ),