Merge branch 'chripede-master' into merging_commits
This commit is contained in:
commit
e2df698099
|
@ -3,3 +3,5 @@ bin
|
||||||
*.json
|
*.json
|
||||||
|
|
||||||
Manifest
|
Manifest
|
||||||
|
.idea
|
||||||
|
smartctl_exporter
|
||||||
|
|
11
main.go
11
main.go
|
@ -36,6 +36,17 @@ func (i SMARTctlManagerCollector) Collect(ch chan<- prometheus.Metric) {
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
options = loadOptions()
|
options = loadOptions()
|
||||||
|
|
||||||
|
if len(options.SMARTctl.Devices) == 0 {
|
||||||
|
logger.Debug("No devices specified, trying to load them automatically")
|
||||||
|
json := readSMARTctlDevices()
|
||||||
|
devices := json.Get("devices").Array()
|
||||||
|
for _, d := range devices {
|
||||||
|
device := d.Get("name").String()
|
||||||
|
logger.Debug("Found device: %s", device)
|
||||||
|
options.SMARTctl.Devices = append(options.SMARTctl.Devices, device)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
99
metrics.go
99
metrics.go
|
@ -140,6 +140,105 @@ var (
|
||||||
},
|
},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
metricDevicePercentageUsed = prometheus.NewDesc(
|
||||||
|
"smartctl_device_percentage_used",
|
||||||
|
"Device write percentage used",
|
||||||
|
[]string{
|
||||||
|
"device",
|
||||||
|
"model_family",
|
||||||
|
"model_name",
|
||||||
|
"serial_number",
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
metricDeviceAvailableSpare = prometheus.NewDesc(
|
||||||
|
"smartctl_device_available_spare",
|
||||||
|
"Normalized percentage (0 to 100%) of the remaining spare capacity available",
|
||||||
|
[]string{
|
||||||
|
"device",
|
||||||
|
"model_family",
|
||||||
|
"model_name",
|
||||||
|
"serial_number",
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
metricDeviceAvailableSpareThreshold = prometheus.NewDesc(
|
||||||
|
"smartctl_device_available_spare_threshold",
|
||||||
|
"When the Available Spare falls below the threshold indicated in this field, an asynchronous event completion may occur. The value is indicated as a normalized percentage (0 to 100%)",
|
||||||
|
[]string{
|
||||||
|
"device",
|
||||||
|
"model_family",
|
||||||
|
"model_name",
|
||||||
|
"serial_number",
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
metricDeviceCriticalWarning = prometheus.NewDesc(
|
||||||
|
"smartctl_device_critical_warning",
|
||||||
|
"This field indicates critical warnings for the state of the controller",
|
||||||
|
[]string{
|
||||||
|
"device",
|
||||||
|
"model_family",
|
||||||
|
"model_name",
|
||||||
|
"serial_number",
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
metricDeviceMediaErrors = prometheus.NewDesc(
|
||||||
|
"smartctl_device_media_errors",
|
||||||
|
"Contains the number of occurrences where the controller detected an unrecovered data integrity error. Errors such as uncorrectable ECC, CRC checksum failure, or LBA tag mismatch are included in this field",
|
||||||
|
[]string{
|
||||||
|
"device",
|
||||||
|
"model_family",
|
||||||
|
"model_name",
|
||||||
|
"serial_number",
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
metricDeviceNumErrLogEntries = prometheus.NewDesc(
|
||||||
|
"smartctl_device_num_err_log_entries",
|
||||||
|
"Contains the number of Error Information log entries over the life of the controller",
|
||||||
|
[]string{
|
||||||
|
"device",
|
||||||
|
"model_family",
|
||||||
|
"model_name",
|
||||||
|
"serial_number",
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
metricDeviceBytesRead = prometheus.NewDesc(
|
||||||
|
"smartctl_device_bytes_read",
|
||||||
|
"",
|
||||||
|
[]string{
|
||||||
|
"device",
|
||||||
|
"model_family",
|
||||||
|
"model_name",
|
||||||
|
"serial_number",
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
metricDeviceBytesWritten = prometheus.NewDesc(
|
||||||
|
"smartctl_device_bytes_written",
|
||||||
|
"",
|
||||||
|
[]string{
|
||||||
|
"device",
|
||||||
|
"model_family",
|
||||||
|
"model_name",
|
||||||
|
"serial_number",
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
metricDeviceSmartStatus = prometheus.NewDesc(
|
||||||
|
"smartctl_device_smart_status",
|
||||||
|
"General smart status",
|
||||||
|
[]string{
|
||||||
|
"device",
|
||||||
|
"model_family",
|
||||||
|
"model_name",
|
||||||
|
"serial_number",
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
)
|
||||||
metricDeviceExitStatus = prometheus.NewDesc(
|
metricDeviceExitStatus = prometheus.NewDesc(
|
||||||
"smartctl_device_smartctl_exit_status",
|
"smartctl_device_smartctl_exit_status",
|
||||||
"Exit status of smartctl on device",
|
"Exit status of smartctl on device",
|
||||||
|
|
|
@ -55,6 +55,15 @@ func readSMARTctl(device string) gjson.Result {
|
||||||
return parseJSON(string(out))
|
return parseJSON(string(out))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func readSMARTctlDevices() gjson.Result {
|
||||||
|
logger.Debug("Collecting devices")
|
||||||
|
out, err := exec.Command(options.SMARTctl.SMARTctlLocation, "--json", "--scan-open").Output()
|
||||||
|
if err != nil {
|
||||||
|
logger.Warning("S.M.A.R.T. output reading error: %s", err)
|
||||||
|
}
|
||||||
|
return parseJSON(string(out))
|
||||||
|
}
|
||||||
|
|
||||||
// Select json source and parse
|
// Select json source and parse
|
||||||
func readData(device string) gjson.Result {
|
func readData(device string) gjson.Result {
|
||||||
if options.SMARTctl.FakeJSON {
|
if options.SMARTctl.FakeJSON {
|
||||||
|
|
120
smartctl.go
120
smartctl.go
|
@ -57,6 +57,16 @@ func (smart *SMARTctl) Collect() {
|
||||||
smart.mineDeviceErrorLog()
|
smart.mineDeviceErrorLog()
|
||||||
smart.mineDeviceSelfTestLog()
|
smart.mineDeviceSelfTestLog()
|
||||||
smart.mineDeviceERC()
|
smart.mineDeviceERC()
|
||||||
|
smart.minePercentageUsed()
|
||||||
|
smart.mineAvailableSpare()
|
||||||
|
smart.mineAvailableSpareThreshold()
|
||||||
|
smart.mineCriticalWarning()
|
||||||
|
smart.mineMediaErrors()
|
||||||
|
smart.mineNumErrLogEntries()
|
||||||
|
smart.mineBytesRead()
|
||||||
|
smart.mineBytesWritten()
|
||||||
|
smart.mineSmartStatus()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (smart *SMARTctl) mineExitStatus() {
|
func (smart *SMARTctl) mineExitStatus() {
|
||||||
|
@ -252,6 +262,116 @@ func (smart *SMARTctl) mineDeviceSCTStatus() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (smart *SMARTctl) minePercentageUsed() {
|
||||||
|
smart.ch <- prometheus.MustNewConstMetric(
|
||||||
|
metricDevicePercentageUsed,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
smart.json.Get("nvme_smart_health_information_log.percentage_used").Float(),
|
||||||
|
smart.device.device,
|
||||||
|
smart.device.family,
|
||||||
|
smart.device.model,
|
||||||
|
smart.device.serial,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (smart *SMARTctl) mineAvailableSpare() {
|
||||||
|
smart.ch <- prometheus.MustNewConstMetric(
|
||||||
|
metricDeviceAvailableSpare,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
smart.json.Get("nvme_smart_health_information_log.available_spare").Float(),
|
||||||
|
smart.device.device,
|
||||||
|
smart.device.family,
|
||||||
|
smart.device.model,
|
||||||
|
smart.device.serial,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (smart *SMARTctl) mineAvailableSpareThreshold() {
|
||||||
|
smart.ch <- prometheus.MustNewConstMetric(
|
||||||
|
metricDeviceAvailableSpareThreshold,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
smart.json.Get("nvme_smart_health_information_log.available_spare_threshold").Float(),
|
||||||
|
smart.device.device,
|
||||||
|
smart.device.family,
|
||||||
|
smart.device.model,
|
||||||
|
smart.device.serial,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (smart *SMARTctl) mineCriticalWarning() {
|
||||||
|
smart.ch <- prometheus.MustNewConstMetric(
|
||||||
|
metricDeviceCriticalWarning,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
smart.json.Get("nvme_smart_health_information_log.critical_warning").Float(),
|
||||||
|
smart.device.device,
|
||||||
|
smart.device.family,
|
||||||
|
smart.device.model,
|
||||||
|
smart.device.serial,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (smart *SMARTctl) mineMediaErrors() {
|
||||||
|
smart.ch <- prometheus.MustNewConstMetric(
|
||||||
|
metricDeviceMediaErrors,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
smart.json.Get("nvme_smart_health_information_log.media_errors").Float(),
|
||||||
|
smart.device.device,
|
||||||
|
smart.device.family,
|
||||||
|
smart.device.model,
|
||||||
|
smart.device.serial,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (smart *SMARTctl) mineNumErrLogEntries() {
|
||||||
|
smart.ch <- prometheus.MustNewConstMetric(
|
||||||
|
metricDeviceNumErrLogEntries,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
smart.json.Get("nvme_smart_health_information_log.num_err_log_entries").Float(),
|
||||||
|
smart.device.device,
|
||||||
|
smart.device.family,
|
||||||
|
smart.device.model,
|
||||||
|
smart.device.serial,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (smart *SMARTctl) mineBytesRead() {
|
||||||
|
blockSize := smart.json.Get("logical_block_size").Float() * 1024
|
||||||
|
smart.ch <- prometheus.MustNewConstMetric(
|
||||||
|
metricDeviceBytesRead,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
smart.json.Get("nvme_smart_health_information_log.data_units_read").Float()*blockSize,
|
||||||
|
smart.device.device,
|
||||||
|
smart.device.family,
|
||||||
|
smart.device.model,
|
||||||
|
smart.device.serial,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (smart *SMARTctl) mineBytesWritten() {
|
||||||
|
blockSize := smart.json.Get("logical_block_size").Float() * 1024
|
||||||
|
smart.ch <- prometheus.MustNewConstMetric(
|
||||||
|
metricDeviceBytesWritten,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
smart.json.Get("nvme_smart_health_information_log.data_units_written").Float()*blockSize,
|
||||||
|
smart.device.device,
|
||||||
|
smart.device.family,
|
||||||
|
smart.device.model,
|
||||||
|
smart.device.serial,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (smart *SMARTctl) mineSmartStatus() {
|
||||||
|
smart.ch <- prometheus.MustNewConstMetric(
|
||||||
|
metricDeviceSmartStatus,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
smart.json.Get("smart_status.passed").Float(),
|
||||||
|
smart.device.device,
|
||||||
|
smart.device.family,
|
||||||
|
smart.device.model,
|
||||||
|
smart.device.serial,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
func (smart *SMARTctl) mineDeviceStatistics() {
|
func (smart *SMARTctl) mineDeviceStatistics() {
|
||||||
for _, page := range smart.json.Get("ata_device_statistics.pages").Array() {
|
for _, page := range smart.json.Get("ata_device_statistics.pages").Array() {
|
||||||
table := strings.TrimSpace(page.Get("name").String())
|
table := strings.TrimSpace(page.Get("name").String())
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
smartctl_exporter:
|
smartctl_exporter:
|
||||||
bind_to: "[::1]:9633"
|
bind_to: "0.0.0.0:9633"
|
||||||
url_path: "/metrics"
|
url_path: "/metrics"
|
||||||
fake_json: no
|
fake_json: no
|
||||||
smartctl_location: /usr/sbin/smartctl
|
smartctl_location: /usr/sbin/smartctl
|
||||||
collect_not_more_than_period: 20s
|
collect_not_more_than_period: 20s
|
||||||
devices:
|
# devices:
|
||||||
- /dev/sda
|
# - /dev/nvme0
|
||||||
- /dev/sdb
|
# - /dev/nvme1
|
||||||
- /dev/sdc
|
# - /dev/nvme2
|
||||||
- /dev/sdd
|
# - /dev/nvme3
|
||||||
- /dev/sde
|
|
||||||
- /dev/sdf
|
|
||||||
|
|
Loading…
Reference in New Issue