Class: ServerMetrics::Disk
- Inherits:
-
MultiCollector
- Object
- Collector
- MultiCollector
- ServerMetrics::Disk
- Defined in:
- lib/server_metrics/collectors/disk.rb
Overview
Collects Disk metrics on eligible filesystems. Reports a hash of hashes, with the first hash keyed by device name.
TODO: Currently, this reports on devices that begins with /dev as listed by ‘mount`. Revisit this. TODO: relies on /proc/diskstats, so not mac compatible. Figure out mac compatibility
Instance Attribute Summary
Attributes inherited from Collector
Instance Method Summary collapse
- #build_report ⇒ Object
-
#devices ⇒ Object
System calls are slow.
-
#df_output ⇒ Object
System calls are slow.
-
#get_io_stats(device_name) ⇒ Object
called from build_report for each device.
-
#get_sizes(device) ⇒ Object
called from build_report for each device.
Methods inherited from MultiCollector
#counter, #memory, #remember, #report
Methods inherited from Collector
#convert_to_mb, #counter, from_hash, #initialize, #linux?, #memory, #option, #osx?, #remember, #report, #run, #to_hash
Constructor Details
This class inherits a constructor from ServerMetrics::Collector
Instance Method Details
#build_report ⇒ Object
10 11 12 13 14 15 16 17 18 19 |
# File 'lib/server_metrics/collectors/disk.rb', line 10 def build_report # forcing English for parsing ENV['LC_ALL'] = 'C' ENV['LANG'] = 'C' devices.each do |device| get_sizes(device) # does its own reporting get_io_stats(device[:name]) if linux? # does its own reporting end end |
#devices ⇒ Object
System calls are slow. Read once every minute and not on every innvocation.
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/server_metrics/collectors/disk.rb', line 32 def devices if @devices.nil? or @last_devices_output < (Time.now-[:ttl].to_i*60) @last_devices_output = Time.now # if running inside a docker container, we want the devices mounted on the host mount_output = dockerized_agent? ? `cat /host/etc/mtab` : `mount` @devices = mount_output.split("\n").grep(/^\/dev/).map{|l| {:name => l.split.first, :aliases => []}} # any device that starts with /dev if dockerized_agent? `blkid`.split("\n").grep(/ UUID=/).each do |device| name = device.match(/\A[^\:]*/)[0] uuid = device.match(/\ UUID="(.+?)"/)[1] if host_device = @devices.find { |dn| dn[:name] == name } host_device[:aliases] << "/dev/disk/by-uuid/#{uuid}" end end end end @devices end |
#df_output ⇒ Object
System calls are slow. Read once every minute and not on every innvocation.
22 23 24 25 26 27 28 29 |
# File 'lib/server_metrics/collectors/disk.rb', line 22 def df_output if @last_df_output.nil? or @last_df_output < (Time.now-[:ttl].to_i*60) @last_df_output = Time.now @df_output = `df -Pkh`.lines.to_a else @df_output end end |
#get_io_stats(device_name) ⇒ Object
called from build_report for each device
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/server_metrics/collectors/disk.rb', line 81 def get_io_stats(device_name) stats = iostat(device_name) if stats counter(device_name, :rps, stats['rio'], :per => :second) counter(device_name, :wps, stats['wio'], :per => :second) counter(device_name, :rps_kb, stats['rsect'] / 2, :per => :second) counter(device_name, :wps_kb, stats['wsect'] / 2, :per => :second) counter(device_name, :utilization, stats['use'] / 10.0, :per => :second) # Not 100% sure that average queue length is present on all distros. if stats['aveq'] counter(device_name, :average_queue_length, stats['aveq'], :per => :second) end if old = memory(device_name, "stats") ios = (stats['rio'] - old['rio']) + (stats['wio'] - old['wio']) if ios > 0 await = ((stats['ruse'] - old['ruse']) + (stats['wuse'] - old['wuse'])) / ios.to_f report(device_name, :await => await) end end remember(device_name, "stats" => stats) end end |
#get_sizes(device) ⇒ Object
called from build_report for each device
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/server_metrics/collectors/disk.rb', line 52 def get_sizes(device) header_line=df_output.first headers = header_line.split(/\s+/,6) # limit to 6 columns - last column is "mounted on" parsed_lines=[] # Each line will look like {"%iused" => "38%","Avail" => "289Gi", "Capacity=> "38%", "Filesystem"=> "/dev/disk0s2","Mounted => "/", "Size" => "465Gi", "Used" => "176Gi", "ifree" => "75812051", "iused" => "46116178"} df_output[1..df_output.size-1].each do |line| values=line.split(/\s+/,6) parsed_lines<<Hash[*headers.zip(values).flatten] end # select the right line hash = parsed_lines.find {|l| l["Filesystem"] == device[:name]} # device wasn't found. check device aliases if hash.nil? hash = parsed_lines.find {|l| device[:aliases].include?(l["Filesystem"])} end # device wasn't found. could be a mapped device. skip over. return if hash.nil? result = {} hash.each_pair do |key,value| key=normalize_key(key) # downcase, make a symbol, etc value = convert_to_mb(value) if [:avail, :capacity, :size, :used].include?(key) result[key]=value end report(device[:name], result) end |