|
| 1 | +#!/bin/bash |
| 2 | +# Script informed by the collectd monitoring script for smartmontools (using smartctl) |
| 3 | +# by Samuel B. <samuel_._behan_(at)_dob_._sk> (c) 2012 |
| 4 | +# source at: http://devel.dob.sk/collectd-scripts/ |
| 5 | + |
| 6 | +# TODO: This probably needs to be a little more complex. The raw numbers can have more |
| 7 | +# data in them than you'd think. |
| 8 | +# http://arstechnica.com/civis/viewtopic.php?p=22062211 |
| 9 | + |
| 10 | +disks="$(/usr/sbin/smartctl --scan | awk '{print $1 "|" $3}')" |
| 11 | + |
| 12 | +parse_smartctl_attributes_awk="$(cat << 'SMARTCTLAWK' |
| 13 | +$1 ~ /^[0-9]+$/ && $2 ~ /^[a-zA-Z0-9_-]+$/ { |
| 14 | + gsub(/-/, "_"); |
| 15 | + printf "%s_value{%s,smart_id=\"%s\"} %d\n", $2, labels, $1, $4 |
| 16 | + printf "%s_worst{%s,smart_id=\"%s\"} %d\n", $2, labels, $1, $5 |
| 17 | + printf "%s_threshold{%s,smart_id=\"%s\"} %d\n", $2, labels, $1, $6 |
| 18 | + printf "%s_raw_value{%s,smart_id=\"%s\"} %d\n", $2, labels, $1, $10 |
| 19 | +} |
| 20 | +SMARTCTLAWK |
| 21 | +)" |
| 22 | + |
| 23 | +smartmon_attrs="$(cat << 'SMARTMONATTRS' |
| 24 | +airflow_temperature_cel |
| 25 | +command_timeout |
| 26 | +current_pending_sector |
| 27 | +end_to_end_error |
| 28 | +erase_fail_count |
| 29 | +g_sense_error_rate |
| 30 | +hardware_ecc_recovered |
| 31 | +host_reads_mib |
| 32 | +host_reads_32mib |
| 33 | +host_writes_mib |
| 34 | +host_writes_32mib |
| 35 | +load_cycle_count |
| 36 | +media_wearout_indicator |
| 37 | +nand_writes_1gib |
| 38 | +offline_uncorrectable |
| 39 | +power_cycle_count |
| 40 | +power_on_hours |
| 41 | +program_fail_count |
| 42 | +raw_read_error_rate |
| 43 | +reallocated_sector_ct |
| 44 | +reported_uncorrect |
| 45 | +sata_downshift_count |
| 46 | +spin_retry_count |
| 47 | +spin_up_time |
| 48 | +start_stop_count |
| 49 | +temperature_celsius |
| 50 | +total_lbas_read |
| 51 | +total_lbas_written |
| 52 | +udma_crc_error_count |
| 53 | +unsafe_shutdown_count |
| 54 | +workld_host_reads_perc |
| 55 | +workld_media_wear_indic |
| 56 | +workload_minutes |
| 57 | +SMARTMONATTRS |
| 58 | +)" |
| 59 | +smartmon_attrs="$(echo ${smartmon_attrs} | xargs | tr ' ' '|')" |
| 60 | + |
| 61 | +parse_smartctl_attributes() { |
| 62 | + local disk="$1" |
| 63 | + local disk_type="$2" |
| 64 | + local labels="disk=\"${disk}\",type=\"${disk_type}\"" |
| 65 | + local vars="$(echo "${smartmon_attrs}" | xargs | tr ' ' '|')" |
| 66 | + sed 's/^ \+//g' \ |
| 67 | + | awk -v labels="${labels}" "${parse_smartctl_attributes_awk}" 2>/dev/null \ |
| 68 | + | tr A-Z a-z \ |
| 69 | + | grep -E "(${smartmon_attrs})" |
| 70 | +} |
| 71 | + |
| 72 | +parse_smartctl_info() { |
| 73 | + local -i smart_available=0 smart_enabled=0 |
| 74 | + local disk="$1" disk_type="$2" |
| 75 | + while read line ; do |
| 76 | + info_type="$(echo "${line}" | cut -f1 -d: | tr ' ' '_')" |
| 77 | + info_value="$(echo "${line}" | cut -f2- -d: | sed 's/^ \+//g')" |
| 78 | + case "${info_type}" in |
| 79 | + Model_Family) model_family="${info_value}" ;; |
| 80 | + Device_Model) device_model="${info_value}" ;; |
| 81 | + Serial_Number) serial_number="${info_value}" ;; |
| 82 | + Firmware_Version) fw_version="${info_value}" ;; |
| 83 | + Vendor) vendor="${info_value}" ;; |
| 84 | + Product) product="${info_value}" ;; |
| 85 | + Revision) revision="${info_value}" ;; |
| 86 | + Logical_Unit_id) lun_id="${info_value}" ;; |
| 87 | + esac |
| 88 | + if [[ "${info_type}" == 'SMART_support_is' ]] ; then |
| 89 | + case "${info_value:0:7}" in |
| 90 | + Enabled) smart_enabled=1 ;; |
| 91 | + Availab) smart_available=1 ;; |
| 92 | + Unavail) smart_available=0 ;; |
| 93 | + esac |
| 94 | + fi |
| 95 | + done |
| 96 | + if [[ -n "${model_family}" ]] ; then |
| 97 | + echo "device_info{disk=\"${disk}\",type=\"${disk_type}\",model_family=\"${model_family}\",device_model=\"${device_model}\",serial_number=\"${serial_number}\",firmware_version=\"${fw_version}\"} 1" |
| 98 | + elif [[ -n "${vendor}" ]] ; then |
| 99 | + echo "device_info{disk=\"${disk}\",type=\"${disk_type}\",vendor=\"${vendor}\",product=\"${product}\",revision=\"${revision}\",lun_id=\"${lun_id}\"} 1" |
| 100 | + fi |
| 101 | + echo "device_smart_available{disk=\"${disk}\",type=\"${disk_type}\"} ${smart_available}" |
| 102 | + echo "device_smart_enabled{disk=\"${disk}\",type=\"${disk_type}\"} ${smart_enabled}" |
| 103 | +} |
| 104 | + |
| 105 | +output_format_awk="$(cat << 'OUTPUTAWK' |
| 106 | +BEGIN { v = "" } |
| 107 | +v != $1 { |
| 108 | + print "# HELP smartmon_" $1 " SMART metric " $1; |
| 109 | + print "# TYPE smartmon_" $1 " gauge"; |
| 110 | + v = $1 |
| 111 | +} |
| 112 | +{print "smartmon_" $0} |
| 113 | +OUTPUTAWK |
| 114 | +)" |
| 115 | + |
| 116 | +format_output() { |
| 117 | + sort \ |
| 118 | + | awk -F'{' "${output_format_awk}" |
| 119 | +} |
| 120 | + |
| 121 | +smartctl_version="$(/usr/sbin/smartctl -V | head -n1 | awk '$1 == "smartctl" {print $2}')" |
| 122 | + |
| 123 | +echo "smartctl_version{version=\"${smartctl_version}\"} 1" | format_output |
| 124 | + |
| 125 | +if [[ "$(expr "${smartctl_version}" : '\([0-9]*\)\..*')" -lt 6 ]] ; then |
| 126 | + exit |
| 127 | +fi |
| 128 | + |
| 129 | +device_list="$(/usr/sbin/smartctl --scan-open | awk '{print $1 "|" $3}')" |
| 130 | + |
| 131 | +for device in ${device_list}; do |
| 132 | + disk="$(echo ${device} | cut -f1 -d'|')" |
| 133 | + type="$(echo ${device} | cut -f2 -d'|')" |
| 134 | + echo "smartctl_run{disk=\"${disk}\",type=\"${type}\"}" $(TZ=UTC date '+%s') |
| 135 | + # Get the SMART information |
| 136 | + /usr/sbin/smartctl -i -d "${type}" "${disk}" | parse_smartctl_info "${disk}" "${type}" |
| 137 | + # Get the SMART attributes |
| 138 | + /usr/sbin/smartctl -A -d "${type}" "${disk}" | parse_smartctl_attributes "${disk}" "${type}" |
| 139 | +done | format_output |
0 commit comments