├── .gitignore ├── .rspec ├── Gemfile ├── LICENSE ├── README.md ├── Rakefile ├── lib ├── munin-ruby.rb └── munin-ruby │ ├── cache.rb │ ├── connection.rb │ ├── errors.rb │ ├── node.rb │ ├── parser.rb │ └── version.rb ├── munin-ruby.gemspec └── spec ├── fixtures ├── config.txt ├── fetch.txt ├── list.txt └── version.txt ├── node_spec.rb ├── parser_spec.rb └── spec_helper.rb /.gitignore: -------------------------------------------------------------------------------- 1 | !.gitignore 2 | *.gem 3 | *.rbc 4 | *.sw[a-p] 5 | *.tmproj 6 | *.tmproject 7 | *.un~ 8 | *~ 9 | .DS_Store 10 | .Spotlight-V100 11 | .Trashes 12 | ._* 13 | .bundle 14 | .config 15 | .directory 16 | .elc 17 | .redcar 18 | .yardoc 19 | /.emacs.desktop 20 | /.emacs.desktop.lock 21 | Desktop.ini 22 | Gemfile.lock 23 | Icon? 24 | InstalledFiles 25 | Session.vim 26 | Thumbs.db 27 | \#*\# 28 | _yardoc 29 | auto-save-list 30 | coverage 31 | doc/ 32 | lib/bundler/man 33 | lib/test.rb 34 | pkg 35 | pkg/* 36 | rdoc 37 | spec/reports 38 | test/tmp 39 | test/version_tmp 40 | tmp 41 | tmtags 42 | tramp -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --backtrace 3 | --format=nested -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | gemspec -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011-2013 Dan Sosedoff 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Munin-Ruby 2 | 3 | Munin-ruby is a sockets-based ruby client library to communicate and fetch 4 | information from munin-node servers. 5 | 6 | ## Installation 7 | 8 | Simple install using rubygems: 9 | 10 | ``` 11 | gem install munin-ruby 12 | ``` 13 | 14 | ## Usage 15 | 16 | Just require the gem and you're good to go. 17 | 18 | ```ruby 19 | require 'munin-ruby' 20 | 21 | node = Munin::Node.new 22 | node.version # => 1.4.4 23 | ``` 24 | 25 | ### Connections 26 | 27 | ```ruby 28 | # Connects to 127.0.0.1:4949 29 | node = Munin::Node.new 30 | node = Munin::Node.new('YOUR_HOST', YOUR_PORT) 31 | ``` 32 | 33 | If munin-node has any restrictions on IP addresses, client will trigger ```Munin::AccessDenied``` 34 | exception. 35 | 36 | By default client will reconnect if connection was lost. To disable that 37 | specify ```false``` after port option. 38 | 39 | ```ruby 40 | node = Munin::Node.new('YOUR_HOST', 4949, false) 41 | ``` 42 | 43 | Ways to disconnect: 44 | 45 | ``` 46 | # Disconnect from server 47 | node.disconnect 48 | node.connection.close 49 | ``` 50 | 51 | In case if automatic reconnection was enabled, service will establish 52 | connection even after you call 'disconnect' method. 53 | 54 | To force client not to open connection: ```node.disconnect(false)```. 55 | 56 | This will trigger ```Munin::ConnectionError``` on any client calls. 57 | 58 | ### Services and metrics 59 | 60 | See what's available on server: 61 | 62 | ```ruby 63 | services = node.list 64 | 65 | # => ["cpu","df", "df_inode", "entropy", "forks", ...] 66 | ``` 67 | 68 | #### Get service configuration 69 | 70 | ```ruby 71 | config = node.config('cpu') 72 | ``` 73 | 74 | This will produce the following result: 75 | 76 | ``` 77 | {"graph"=> 78 | {"title"=>"CPU usage", 79 | "order"=>"system user nice idle iowait irq softirq", 80 | "args"=> 81 | {"raw"=>"--base 1000 -r --lower-limit 0 --upper-limit 400", 82 | "parsed"=>{"base"=>"1000", "lower-limit"=>"0", "upper-limit"=>"400"}}, 83 | "vlabel"=>"%", 84 | "scale"=>"no", 85 | "info"=>"This graph shows how CPU time is spent.", 86 | "category"=>"system", 87 | "period"=>"second"}, 88 | "metrics"=> 89 | {"system"=> 90 | {"label"=>"system", 91 | "draw"=>"AREA", 92 | "min"=>"0", 93 | "type"=>"DERIVE", 94 | "info"=>"CPU time spent by the kernel in system activities"}, 95 | "user"=> 96 | {"label"=>"user", 97 | "draw"=>"STACK", 98 | "min"=>"0", 99 | "type"=>"DERIVE", 100 | "info"=>"CPU time spent by normal programs and daemons"}, 101 | "nice"=> 102 | {"label"=>"nice", 103 | "draw"=>"STACK", 104 | "min"=>"0", 105 | "type"=>"DERIVE", 106 | "info"=>"CPU time spent by nice(1)d programs"}, 107 | "idle"=> 108 | {"label"=>"idle", 109 | "draw"=>"STACK", 110 | "min"=>"0", 111 | "type"=>"DERIVE", 112 | "info"=>"Idle CPU time"}, 113 | "iowait"=> 114 | {"label"=>"iowait", 115 | "draw"=>"STACK", 116 | "min"=>"0", 117 | "type"=>"DERIVE", 118 | "info"=> 119 | "CPU time spent waiting for I/O operations to finish when there is nothing else to do."}, 120 | "irq"=> 121 | {"label"=>"irq", 122 | "draw"=>"STACK", 123 | "min"=>"0", 124 | "type"=>"DERIVE", 125 | "info"=>"CPU time spent handling interrupts"}, 126 | "softirq"=> 127 | {"label"=>"softirq", 128 | "draw"=>"STACK", 129 | "min"=>"0", 130 | "type"=>"DERIVE", 131 | "info"=>"CPU time spent handling \"batched\" interrupts"}, 132 | "steal"=> 133 | {"label"=>"steal", 134 | "draw"=>"STACK", 135 | "min"=>"0", 136 | "type"=>"DERIVE", 137 | "info"=> 138 | "The time that a virtual CPU had runnable tasks, but the virtual CPU itself was not running"}}} 139 | ``` 140 | 141 | #### Fetch a single service 142 | 143 | ```ruby 144 | service = node.fetch('cpu') 145 | ``` 146 | 147 | Output: 148 | 149 | ``` 150 | {"user"=>"140349907", 151 | "nice"=>"0", 152 | "system"=>"19694121", 153 | "idle"=>"536427034", 154 | "iowait"=>"6455996", 155 | "irq"=>"445", 156 | "softirq"=>"482942", 157 | "steal"=>"635801"} 158 | ``` 159 | 160 | 161 | ## License 162 | 163 | Copyright (c) 2011-2013 Dan Sosedoff. 164 | 165 | Permission is hereby granted, free of charge, to any person obtaining a copy of 166 | this software and associated documentation files (the "Software"), to deal in 167 | the Software without restriction, including without limitation the rights to 168 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 169 | the Software, and to permit persons to whom the Software is furnished to do so, 170 | subject to the following conditions: 171 | 172 | The above copyright notice and this permission notice shall be included in all 173 | copies or substantial portions of the Software. 174 | 175 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 176 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 177 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 178 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 179 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 180 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 181 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | 3 | require "bundler" 4 | require "bundler/gem_tasks" 5 | require "rspec/core/rake_task" 6 | 7 | RSpec::Core::RakeTask.new(:spec) do |spec| 8 | spec.pattern = 'spec/*_spec.rb' 9 | end 10 | 11 | task :default => :spec 12 | task :test => :spec -------------------------------------------------------------------------------- /lib/munin-ruby.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'socket' 3 | 4 | begin 5 | require 'system_timer' 6 | rescue LoadError 7 | require 'timeout' 8 | end 9 | 10 | module Munin 11 | TIMEOUT_TIME = 10 12 | 13 | if defined?(SystemTimer) 14 | TIMEOUT_CLASS = SystemTimer 15 | else 16 | TIMEOUT_CLASS = Timeout 17 | end 18 | end 19 | 20 | require 'munin-ruby/version' 21 | require 'munin-ruby/errors' 22 | require 'munin-ruby/parser' 23 | require 'munin-ruby/cache' 24 | require 'munin-ruby/connection' 25 | require 'munin-ruby/node' 26 | 27 | -------------------------------------------------------------------------------- /lib/munin-ruby/cache.rb: -------------------------------------------------------------------------------- 1 | module Munin 2 | module Cache 3 | def cache(key) 4 | raise RuntimeError, "Block required." unless block_given? 5 | data = cache_get(key) 6 | if data.nil? 7 | data = yield 8 | cache_set(key, data) 9 | end 10 | data 11 | end 12 | 13 | def flush_cache 14 | instance_variables.select { |l| l =~ /^@cache_/ }.each do |var| 15 | remove_instance_variable(var) 16 | end 17 | true 18 | end 19 | 20 | protected 21 | 22 | def cache_key(key) 23 | "@cache_#{key.gsub(/[\.-]/,'__')}".to_sym 24 | end 25 | 26 | def cache_get(key) 27 | instance_variable_get(cache_key(key)) 28 | end 29 | 30 | def cache_set(key, value) 31 | instance_variable_set(cache_key(key), value) 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /lib/munin-ruby/connection.rb: -------------------------------------------------------------------------------- 1 | module Munin 2 | class Connection 3 | include Munin::Parser 4 | 5 | DEFAULT_OPTIONS = {:timeout => Munin::TIMEOUT_TIME} 6 | 7 | attr_reader :host, :port 8 | 9 | # Initialize a new connection to munin-node server 10 | # 11 | # host - Server host (default: 127.0.0.1) 12 | # port - Server port (default: 4949) 13 | # options - A hash containing different options 14 | # :timeout => A timeout in seconds to be used in the connection 15 | 16 | def initialize(host='127.0.0.1', port=4949, reconnect=true, options = {}) 17 | @host = host 18 | @port = port 19 | @socket = nil 20 | @connected = false 21 | @reconnect = reconnect 22 | @options = DEFAULT_OPTIONS.merge(options) 23 | end 24 | 25 | # Returns true if socket is connected 26 | # 27 | def connected? 28 | @connected == true 29 | end 30 | 31 | # Establish connection to the server 32 | # 33 | def open 34 | begin 35 | begin 36 | with_timeout do 37 | @socket = TCPSocket.new(@host, @port) 38 | @socket.sync = true 39 | welcome = @socket.gets 40 | unless welcome =~ /^# munin node at/ 41 | raise Munin::AccessDenied 42 | end 43 | @connected = true 44 | end 45 | rescue Timeout::Error 46 | raise Munin::ConnectionError, "Timed out talking to #{@host}" 47 | end 48 | rescue Errno::ETIMEDOUT, Errno::ECONNREFUSED, Errno::ECONNRESET => ex 49 | raise Munin::ConnectionError, ex.message 50 | rescue EOFError 51 | raise Munin::AccessDenied 52 | rescue Exception => ex 53 | raise Munin::ConnectionError, ex.message 54 | end 55 | end 56 | 57 | # Close connection 58 | # 59 | def close(reconnect=true) 60 | if connected? 61 | @socket.flush 62 | @socket.shutdown 63 | @connected = false 64 | @reconnect = reconnect 65 | end 66 | end 67 | 68 | # Send a string of data followed by a newline symbol 69 | # 70 | def send_data(str) 71 | if !connected? 72 | if !@socket.nil? && @reconnect == false 73 | raise Munin::ConnectionError, "Not connected." 74 | else 75 | open 76 | end 77 | end 78 | 79 | begin 80 | with_timeout { @socket.puts("#{str.strip}\n") } 81 | rescue Timeout::Error 82 | raise Munin::ConnectionError, "Timed out on #{@host} trying to send." 83 | end 84 | end 85 | 86 | # Reads a single line from socket 87 | # 88 | def read_line 89 | begin 90 | with_timeout { @socket.gets.to_s.strip } 91 | rescue Errno::ETIMEDOUT, Errno::ECONNREFUSED, Errno::ECONNRESET, EOFError => ex 92 | raise Munin::ConnectionError, ex.message 93 | rescue Timeout::Error 94 | raise Munin::ConnectionError, "Timed out reading from #{@host}." 95 | end 96 | end 97 | 98 | # Reads a packet of data until '.' reached 99 | # 100 | def read_packet 101 | begin 102 | with_timeout do 103 | lines = [] 104 | while(str = @socket.readline.to_s) do 105 | break if str.strip == '.' 106 | lines << str.strip 107 | end 108 | parse_error(lines) 109 | lines 110 | end 111 | rescue Errno::ETIMEDOUT, Errno::ECONNREFUSED, Errno::ECONNRESET, EOFError => ex 112 | raise Munin::ConnectionError, ex.message 113 | rescue Timeout::Error 114 | raise Munin::ConnectionError, "Timed out reading from #{@host}." 115 | end 116 | end 117 | 118 | private 119 | 120 | # Execute operation with timeout 121 | # @param [Block] block Block to execute 122 | def with_timeout(time=@options[:timeout]) 123 | raise ArgumentError, "Block required" if !block_given? 124 | if Munin::TIMEOUT_CLASS.respond_to?(:timeout_after) 125 | Munin::TIMEOUT_CLASS.timeout_after(time) { yield } 126 | else 127 | Munin::TIMEOUT_CLASS.timeout(time) { yield } 128 | end 129 | end 130 | end 131 | end 132 | -------------------------------------------------------------------------------- /lib/munin-ruby/errors.rb: -------------------------------------------------------------------------------- 1 | module Munin 2 | class MuninError < StandardError ; end 3 | class ConnectionError < MuninError ; end 4 | class AccessDenied < MuninError ; end 5 | class InvalidResponse < MuninError ; end 6 | class UnknownService < MuninError ; end 7 | class BadExit < MuninError ; end 8 | end -------------------------------------------------------------------------------- /lib/munin-ruby/node.rb: -------------------------------------------------------------------------------- 1 | require 'digest/md5' 2 | 3 | module Munin 4 | class Node 5 | include Munin::Parser 6 | include Munin::Cache 7 | 8 | attr_reader :connection 9 | 10 | DEFAULT_OPTIONS = {:timeout => Munin::TIMEOUT_TIME} 11 | 12 | # Initialize a new Node instance 13 | # 14 | # host - Server host 15 | # port - Server port 16 | # reconnect - Reconnect if connection was closed (default: true) 17 | # options - A hash containing different options 18 | # :timeout => A timeout in seconds to be used in the connection 19 | def initialize(host='127.0.0.1', port=4949, reconnect=true, options = {}) 20 | @options = DEFAULT_OPTIONS.merge(options) 21 | @connection = Munin::Connection.new(host, port, reconnect, @options) 22 | end 23 | 24 | # Open service connection 25 | # 26 | def connect 27 | connection.open 28 | end 29 | 30 | # Close server connection 31 | # 32 | def disconnect(reconnect=true) 33 | connection.close(reconnect) 34 | end 35 | 36 | # Get a node version 37 | # 38 | def version 39 | cache 'version' do 40 | connection.send_data("version") 41 | parse_version(connection.read_line) 42 | end 43 | end 44 | 45 | # Get a list of all available nodes 46 | # 47 | def nodes 48 | nodes = [] 49 | cache 'nodes' do 50 | connection.send_data("nodes") 51 | while ( ( line = connection.read_line ) != "." ) 52 | nodes << line 53 | end 54 | nodes 55 | end 56 | end 57 | 58 | # Get a list of all available metrics 59 | # 60 | def list(node = "") 61 | cache "list_#{node.empty? ? 'default' : node}" do 62 | connection.send_data("list #{node}") 63 | if ( line = connection.read_line ) != "." 64 | line.split 65 | else 66 | connection.read_line.split 67 | end 68 | end 69 | end 70 | 71 | # Get a configuration information for service 72 | # 73 | # services - Name of the service, or list of service names 74 | # 75 | def config(services, raw=false) 76 | unless [String, Array].include?(services.class) 77 | raise ArgumentError, "Service(s) argument required" 78 | end 79 | 80 | results = {} 81 | names = [services].flatten.uniq 82 | 83 | if names.empty? 84 | raise ArgumentError, "Service(s) argument required" 85 | end 86 | 87 | key = 'config_' + Digest::MD5.hexdigest(names.to_s) + "_#{raw}" 88 | 89 | cache(key) do 90 | names.each do |service| 91 | begin 92 | connection.send_data("config #{service}") 93 | lines = connection.read_packet 94 | results[service] = raw ? lines.join("\n") : parse_config(lines) 95 | rescue UnknownService, BadExit 96 | # TODO 97 | end 98 | end 99 | results 100 | end 101 | end 102 | 103 | # Get all service metrics values 104 | # 105 | # services - Name of the service, or list of service names 106 | # 107 | def fetch(services) 108 | unless [String, Array].include?(services.class) 109 | raise ArgumentError, "Service(s) argument required" 110 | end 111 | 112 | results = {} 113 | names = [services].flatten 114 | 115 | if names.empty? 116 | raise ArgumentError, "Service(s) argument required" 117 | end 118 | 119 | names.each do |service| 120 | begin 121 | connection.send_data("fetch #{service}") 122 | lines = connection.read_packet 123 | results[service] = parse_fetch(lines) 124 | rescue UnknownService, BadExit 125 | # TODO 126 | end 127 | end 128 | results 129 | end 130 | end 131 | end 132 | -------------------------------------------------------------------------------- /lib/munin-ruby/parser.rb: -------------------------------------------------------------------------------- 1 | module Munin 2 | module Parser 3 | # Parse a version request 4 | # 5 | def parse_version(line) 6 | if line =~ /^munins node on/ 7 | line.split.last 8 | else 9 | raise Munin::InvalidResponse, "Invalid version response" 10 | end 11 | end 12 | 13 | # Process response 14 | # 15 | def process_data(lines) 16 | data = {} 17 | lines.each do |line| 18 | line = line.split 19 | key = line.first.split('.value').first 20 | data[key] = line.last 21 | end 22 | data 23 | end 24 | 25 | # Parse 'config' request 26 | # 27 | def parse_config(data) 28 | config = {'graph' => {}, 'metrics' => {}} 29 | data.each do |l| 30 | if l =~ /^graph_/ 31 | key_name, value = l.scan(/^graph_([\w]+)\s(.*)/).flatten 32 | config['graph'][key_name] = value 33 | # according to http://munin-monitoring.org/wiki/notes_on_datasource_names 34 | elsif l =~ /^[a-zA-Z_][a-zA-Z\d_]*\./ 35 | # according to http://munin-monitoring.org/wiki/fieldnames the second one 36 | # can only be [a-z] 37 | matches = l.scan(/^([a-zA-Z_][a-zA-Z\d_]*)\.([a-z]+)\s(.*)/).flatten 38 | config['metrics'][matches[0]] ||= {} 39 | config['metrics'][matches[0]][matches[1]] = matches[2] 40 | end 41 | end 42 | 43 | # Now, lets process the args hash 44 | if config['graph'].key?('args') 45 | config['graph']['args'] = parse_config_args(config['graph']['args']) 46 | end 47 | 48 | config 49 | end 50 | 51 | # Parse 'fetch' request 52 | # 53 | def parse_fetch(data) 54 | process_data(data) 55 | end 56 | 57 | # Detect error from output 58 | # 59 | def parse_error(lines) 60 | if lines.size == 1 61 | case lines.first 62 | when '# Unknown service' then raise UnknownService 63 | when '# Bad exit' then raise BadExit 64 | end 65 | end 66 | end 67 | 68 | # Parse configuration arguments 69 | # 70 | def parse_config_args(args) 71 | result = {} 72 | args.scan(/--?([a-z\-\_]+)\s([\d]+)\s?/).each do |arg| 73 | result[arg.first] = arg.last 74 | end 75 | {'raw' => args, 'parsed' => result} 76 | end 77 | end 78 | end 79 | -------------------------------------------------------------------------------- /lib/munin-ruby/version.rb: -------------------------------------------------------------------------------- 1 | module Munin 2 | unless defined?(::Munin::VERSION) 3 | VERSION = '0.2.5' 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /munin-ruby.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | require File.expand_path('../lib/munin-ruby/version', __FILE__) 3 | 4 | Gem::Specification.new do |gem| 5 | gem.name = "munin-ruby" 6 | gem.version = Munin::VERSION.dup 7 | gem.author = "Dan Sosedoff" 8 | gem.email = "dan.sosedoff@gmail.com" 9 | gem.homepage = "http://github.com/sosedoff/munin-ruby" 10 | gem.description = "Munin Node client" 11 | gem.summary = "Ruby client library to communicate with munin-node servers" 12 | 13 | gem.files = `git ls-files`.split("\n") 14 | gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") 15 | gem.executables = `git ls-files -- bin/*`.split("\n").map{|f| File.basename(f)} 16 | gem.require_paths = ['lib'] 17 | 18 | gem.add_development_dependency 'rspec', '~> 2.13' 19 | end -------------------------------------------------------------------------------- /spec/fixtures/config.txt: -------------------------------------------------------------------------------- 1 | config memory 2 | graph_args --base 1024 -l 0 --upper-limit 16175665152 3 | graph_vlabel Bytes 4 | graph_title Memory usage 5 | graph_category system 6 | graph_info This graph shows what the machine uses memory for. 7 | graph_order apps page_tables swap_cache slab cached buffers free swap 8 | apps.label apps 9 | apps.draw AREA 10 | apps.info Memory used by user-space applications. 11 | buffers.label buffers 12 | buffers.draw STACK 13 | buffers.info Block device (e.g. harddisk) cache. Also where "dirty" blocks are stored until written. 14 | swap.label swap 15 | swap.draw STACK 16 | swap.info Swap space used. 17 | cached.label cache 18 | cached.draw STACK 19 | cached.info Parked file data (file content) cache. 20 | free.label unused 21 | free.draw STACK 22 | free.info Wasted memory. Memory that is not used for anything at all. 23 | slab.label slab_cache 24 | slab.draw STACK 25 | slab.info Memory used by the kernel (major users are caches like inode, dentry, etc). 26 | swap_cache.label swap_cache 27 | swap_cache.draw STACK 28 | swap_cache.info A piece of memory that keeps track of pages that have been fetched from swap but not yet been modified. 29 | page_tables.label page_tables 30 | page_tables.draw STACK 31 | page_tables.info Memory used to map between virtual and physical memory addresses. 32 | vmalloc_used.label vmalloc_used 33 | vmalloc_used.draw LINE2 34 | vmalloc_used.info 'VMalloc' (kernel) memory used 35 | committed.label committed 36 | committed.draw LINE2 37 | committed.info The amount of memory allocated to programs. Overcommitting is normal, but may indicate memory leaks. 38 | mapped.label mapped 39 | mapped.draw LINE2 40 | mapped.info All mmap()ed pages. 41 | active.label active 42 | active.draw LINE2 43 | active.info Memory recently used. Not reclaimed unless absolutely necessary. 44 | inactive.label inactive 45 | inactive.draw LINE2 46 | inactive.info Memory not currently used. 47 | . -------------------------------------------------------------------------------- /spec/fixtures/fetch.txt: -------------------------------------------------------------------------------- 1 | fetch memory 2 | slab.value 710025216 3 | swap_cache.value 823296 4 | page_tables.value 27803648 5 | vmalloc_used.value 9228288 6 | apps.value 1219354624 7 | free.value 204206080 8 | buffers.value 2046074880 9 | cached.value 11967377408 10 | swap.value 2961408 11 | committed.value 2358927360 12 | mapped.value 1625862144 13 | active.value 5164363776 14 | inactive.value 10039930880 15 | . 16 | -------------------------------------------------------------------------------- /spec/fixtures/list.txt: -------------------------------------------------------------------------------- 1 | cpu memory load 2 | -------------------------------------------------------------------------------- /spec/fixtures/version.txt: -------------------------------------------------------------------------------- 1 | munins node on hostname version: 1.4.4 -------------------------------------------------------------------------------- /spec/node_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'Munin::Node' do 4 | # TODO 5 | end 6 | -------------------------------------------------------------------------------- /spec/parser_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | class ParseTester 4 | include Munin::Parser 5 | end 6 | 7 | describe Munin::Parser do 8 | before :each do 9 | @parser = ParseTester.new 10 | end 11 | 12 | it 'parses version request' do 13 | @parser.parse_version(fixture('version.txt')).should == '1.4.4' 14 | 15 | proc { @parser.parse_version("some other response") }. 16 | should raise_error Munin::InvalidResponse, "Invalid version response" 17 | end 18 | 19 | it 'parses config request' do 20 | c = @parser.parse_config(fixture('config.txt').strip.split("\n")) 21 | c.should be_a Hash 22 | c['graph'].should be_a Hash 23 | c['graph']['args']['raw'].should == '--base 1024 -l 0 --upper-limit 16175665152' 24 | c['graph']['args']['parsed'].keys.should == %w(base l upper-limit) 25 | c['metrics'].should be_a Hash 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | $:.unshift File.expand_path("../..", __FILE__) 2 | 3 | require 'munin-ruby' 4 | 5 | def fixture_path 6 | File.expand_path("../fixtures", __FILE__) 7 | end 8 | 9 | def fixture(file) 10 | File.read(File.join(fixture_path, file)) 11 | end --------------------------------------------------------------------------------