napolean 1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source :rubygems
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ Copyright (C) 2012 Hubbub Deliveries Ltd.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,34 @@
1
+ # Napolean, lover of metric
2
+
3
+ This is a Ruby tool to collect metrics and submit them to Librato metrics. To make it work you'll need:
4
+
5
+ * Ruby
6
+ * A Librato Metrics account
7
+
8
+ ## Installing
9
+
10
+ Napolean is a Ruby gem, so just run `gem install napolean`, you'll then need to create a config file. By
11
+ default /etc/napolean.conf will be loaded, but you can specify any other path on the command line. It should
12
+ look like this:
13
+
14
+ $librato_username = "bob@example.org"
15
+ $librato_key = "YOUR API KEY"
16
+
17
+ # Provide some MySQL credentials to collect stats on command usage
18
+ # $mysql_username = "root"
19
+ # $mysql_password = "password"
20
+
21
+ # The source to list metrics from. Defaults to the current machine's hostname.
22
+ $source = `hostname --fqdn`.strip
23
+
24
+ # Turn this on for testing so that data doesn't get submitted to Librato.
25
+ $do_not_submit = false
26
+
27
+ # Any Ruby files found in these paths will be loaded and used as collectors.
28
+ # $collector_paths = [ "/usr/libexec/napolean/" ]
29
+
30
+ ## Running Napolean
31
+
32
+ It goes a little something like this: `napolean [/path/to/napolean.conf]`. If you want to use the default
33
+ config file from /etc/napolean.conf just run `napolean`. It'll log to STDOUT, if you want to send it elsewhere
34
+ pipe that to `logger`.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
data/bin/napolean ADDED
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env ruby
2
+ require 'bundler/setup'
3
+ require 'librato/metrics'
4
+ require 'logger'
5
+
6
+ def queue(name, value, type = :gauge)
7
+ $log.info("Tracking #{name} as #{value}")
8
+ $queue.add(name => { :value => value, :source => $source, :type => type, :measure_time => $report_time.to_i })
9
+ end
10
+
11
+ def queue_counter(name, value)
12
+ queue(name, value, :counter)
13
+ end
14
+
15
+ def queue_gauge(name, value)
16
+ queue(name, value, :gauge)
17
+ end
18
+
19
+
20
+ $log = Logger.new(STDOUT)
21
+ $log.level = Logger::DEBUG
22
+
23
+ $log.info("Starting Napolean")
24
+
25
+ config_path = ARGV[0] || "/etc/napolean.conf"
26
+ $log.info("Loading configuration from #{config_path}")
27
+ load(config_path)
28
+
29
+ $log.info("Configuring Librato Metrics for #{$librato_username}")
30
+ Librato::Metrics.authenticate $librato_username, $librato_key
31
+ $queue = Librato::Metrics::Queue.new
32
+
33
+ $start_time = Time.now
34
+
35
+ # Report the time as always being at 0 seconds so values line up in Librato.
36
+ $report_time = Time.gm($start_time.year, $start_time.month, $start_time.day, $start_time.hour, $start_time.min, 0)
37
+
38
+ [ Array($collector_paths), File.expand_path("../../lib/collectors", __FILE__) ].flatten.each do |path|
39
+ $log.info("Loading collectors from #{path}")
40
+ Dir.glob("#{path}/*.rb").each do |collector|
41
+ name = collector.gsub(/^collectors\/(.*)\.rb$/, "\\1")
42
+
43
+ $log.info("Collecting metric: #{name}")
44
+ load(collector)
45
+ end
46
+ end
47
+
48
+ run_time = Time.now - $start_time
49
+ $log.info("Metrics gathering complete in #{run_time} seconds")
50
+ queue_gauge("system.napolean.run_time", run_time)
51
+
52
+ $log.info("Flushing queue")
53
+ unless $do_not_submit
54
+ $queue.submit
55
+ end
data/config.rb ADDED
@@ -0,0 +1,15 @@
1
+ $librato_username = "bob@example.org"
2
+ $librato_key = "YOUR API KEY"
3
+
4
+ $mysql_username = nil
5
+ # $mysql_username = "root" # Provide a username, and optionally a password, to track MySQL commands.
6
+ # $mysql_password = "password"
7
+
8
+ # The source to list metrics from. Defaults to the current machine's hostname.
9
+ $source = `hostname --fqdn`.strip
10
+
11
+ # Turn this on for testing so that data doesn't get submitted to Librato.
12
+ $do_not_submit = true
13
+
14
+ # Any Ruby files found in these paths will be loaded and used as collectors.
15
+ $collector_paths = [ "/usr/libexec/napolean/" ]
@@ -0,0 +1,21 @@
1
+ cmd = `which mpstat`
2
+ if $? == 0
3
+ output = `mpstat 1 1` # Get stats on a single 1 second sample.
4
+ fields = output.split("\n")[3].split(/\s+/)
5
+
6
+ # Some versions of mpstat output time as 01:35:40 PM, while others us a 24 hours clock.
7
+ i = (fields[2] == "all") ? 3 : 2
8
+
9
+ sum = 0
10
+ %w(user nice sys iowait irq soft steal guest).each do |field|
11
+ queue_gauge("system.cpu.#{field}", fields[i])
12
+ sum += fields[i].to_f
13
+
14
+ i += 1
15
+ end
16
+
17
+ queue_gauge("system.cpu.idle", fields[i])
18
+ queue_gauge("system.cpu.total", sum)
19
+ else
20
+ $log.warn("Skipping CPU load because mpstat is not available. Install the sysstat package.")
21
+ end
@@ -0,0 +1,15 @@
1
+ output = `df -m`.split("\n")
2
+
3
+ output.shift
4
+ output.each do |line|
5
+ fields = line.split(/\s+/)
6
+
7
+ device = fields[0]
8
+ mount_point = fields[5].sub(/^\/$/, "root").sub(/^\//, "").gsub(/\//, "-")
9
+
10
+ i = 1
11
+ %w(capacity used available percent_full).each do |field|
12
+ queue_counter("system.disk.#{mount_point}.#{field}", fields[i].sub(/\%$/, ""))
13
+ i += 1
14
+ end
15
+ end
@@ -0,0 +1,26 @@
1
+ cmd = `which mpstat`
2
+ if $? == 0
3
+ output = `iostat 1 2` # Get stats on a single 1 second sample. Run once to flush average since boot.
4
+
5
+ lines = output.split("\n")
6
+ lines.shift # Remove the first line.
7
+
8
+ runs = lines.join("\n").split(/\navg-cpu.*\n/)
9
+
10
+ data = runs.last.split("\n")
11
+ 2.times { data.shift } # CPU stats, and headings
12
+
13
+ data.shift # Drop the headings
14
+ data.each do |device|
15
+ fields = device.split(/\s+/)
16
+ device_name = fields.shift
17
+
18
+ i = 0
19
+ %w(iops kb_read_per_second kb_written_per_second kb_read kb_written).each do |field|
20
+ queue_gauge("system.io.#{device_name}.#{field}", fields[i])
21
+ i += 1
22
+ end
23
+ end
24
+ else
25
+ $log.warn("Skipping IO stats because iostat is not available. Install the sysstat package.")
26
+ end
@@ -0,0 +1,5 @@
1
+ load_avg = File.read("/proc/loadavg").split(" ")
2
+
3
+ queue_gauge("system.load_average.1", load_avg[0])
4
+ queue_gauge("system.load_average.5", load_avg[1])
5
+ queue_gauge("system.load_average.15", load_avg[2])
@@ -0,0 +1,9 @@
1
+ output = File.read("/proc/meminfo")
2
+
3
+ parts = output.split("\n").collect { |l| l.strip.split(/\s+/) }
4
+ stats = parts.inject({}) { |memo, part| memo.merge(part[0].gsub(":", "") => (part[1].to_i / 1024)) }
5
+
6
+ queue_counter("system.memory.total", stats["MemTotal"])
7
+ queue_counter("system.memory.free", stats["MemFree"])
8
+ queue_counter("system.memory.buffers", stats["Buffers"])
9
+ queue_counter("system.memory.cache", stats["Cached"])
@@ -0,0 +1,21 @@
1
+ key_map = {
2
+ "com_delete" => "commands.delete",
3
+ "com_insert" => "commands.insert",
4
+ "com_select" => "commands.select",
5
+ "com_update" => "commands.update",
6
+ }
7
+
8
+ unless $mysql_username.nil?
9
+ cmd = "mysql -e 'SHOW STATUS' -u#{$mysql_username}"
10
+ cmd += " -p#{$mysql_password}" unless $mysql_password.nil?
11
+
12
+ output = `#{cmd}`
13
+ fields = output.split("\n").collect { |l| l.split(/\s+/).collect { |f| f.downcase.strip } }
14
+ data = fields.inject({}) { |memo, f| memo.merge(f[0] => f[1]) }
15
+
16
+ key_map.each do |field, key|
17
+ queue_gauge("mysql.#{key}", data[field])
18
+ end
19
+ else
20
+ $log.info("Skipping MySQL status because no configuration was set")
21
+ end
@@ -0,0 +1,38 @@
1
+ run1 = File.read("/proc/net/dev")
2
+ sleep 1
3
+ run2 = File.read("/proc/net/dev")
4
+
5
+ runs = {}
6
+ [ run1, run2 ].each do |run|
7
+ lines = run.split("\n")
8
+ 2.times { lines.shift }
9
+
10
+ data = lines.collect { |l| l.split(/\s+/) }
11
+ data.each do |line|
12
+ line.shift
13
+ ifname = line.shift.gsub(/:$/, "")
14
+
15
+ runs[ifname] ||= []
16
+ runs[ifname] << line
17
+ end
18
+ end
19
+
20
+ averages = {}
21
+ runs.each do |ifname, data|
22
+ run1, run2 = data
23
+ last_second = []
24
+
25
+ i = 0
26
+ while i < 17
27
+ last_second << (run2[i].to_i - run1[i].to_i)
28
+ i += 1
29
+ end
30
+
31
+ averages[ifname] = last_second
32
+ end
33
+
34
+ { :rx_bytes => 0, :tx_bytes => 8, :rx_errors => 2, :tx_errors => 10 }.each do |field, idx|
35
+ averages.keys.each do |interface|
36
+ queue_counter("system.net.#{interface}.#{field}", averages[interface][idx])
37
+ end
38
+ end
@@ -0,0 +1,5 @@
1
+ uptime_in_seconds = File.read("/proc/uptime").split(" ")[0].to_f
2
+
3
+ $log.debug("Uptime in seconds: #{uptime_in_seconds}")
4
+ $log.debug("Uptime in minutes: #{uptime_in_seconds/60}")
5
+ queue_counter("system.minutes_uptime", (uptime_in_seconds/60).to_i)
data/napolean.gemspec ADDED
@@ -0,0 +1,18 @@
1
+ lib = File.expand_path("../lib", __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.name = "napolean"
6
+ gem.version = "1.0"
7
+ gem.authors = [ "Jon Wood" ]
8
+ gem.email = [ "jon@hubbub.co.uk" ]
9
+ gem.description = %q{A tool to collect and submit system metrics to Librato Metrics}
10
+ gem.summary = %q{A tool to collect and submit system metrics to Librato Metrics}
11
+ gem.homepage = "http://github.com/hubbub/napolean"
12
+
13
+ gem.files = `git ls-files`.split($/)
14
+ gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
15
+ gem.require_paths = [ "lib" ]
16
+
17
+ gem.add_dependency "librato-metrics"
18
+ end
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: napolean
3
+ version: !ruby/object:Gem::Version
4
+ version: '1.0'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jon Wood
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-11-26 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: librato-metrics
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ description: A tool to collect and submit system metrics to Librato Metrics
31
+ email:
32
+ - jon@hubbub.co.uk
33
+ executables:
34
+ - napolean
35
+ extensions: []
36
+ extra_rdoc_files: []
37
+ files:
38
+ - .gitignore
39
+ - Gemfile
40
+ - LICENSE
41
+ - README.md
42
+ - Rakefile
43
+ - bin/napolean
44
+ - config.rb
45
+ - lib/collectors/cpu_load.rb
46
+ - lib/collectors/disk_usage.rb
47
+ - lib/collectors/io_stat.rb
48
+ - lib/collectors/load_average.rb
49
+ - lib/collectors/memory.rb
50
+ - lib/collectors/mysql.rb
51
+ - lib/collectors/network.rb
52
+ - lib/collectors/uptime.rb
53
+ - napolean.gemspec
54
+ homepage: http://github.com/hubbub/napolean
55
+ licenses: []
56
+ post_install_message:
57
+ rdoc_options: []
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ! '>='
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ requirements: []
73
+ rubyforge_project:
74
+ rubygems_version: 1.8.24
75
+ signing_key:
76
+ specification_version: 3
77
+ summary: A tool to collect and submit system metrics to Librato Metrics
78
+ test_files: []