neutrino_client 0.0.3 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -10,11 +10,10 @@ module Neutrino
10
10
  property :group
11
11
  property :type
12
12
  property :name
13
- property :value
13
+ property :values
14
14
  property :display_options
15
15
 
16
16
  def metric_id
17
- raise StandardError.new("Requires name and hostname") unless name && hostname
18
17
  Digest::MD5.hexdigest("#{name}#{hostname}")
19
18
  end
20
19
 
@@ -23,15 +22,19 @@ module Neutrino
23
22
  end
24
23
 
25
24
  def to_h
25
+ raise StandardError.new("Requires name") unless name
26
+ raise StandardError.new("Requires values") unless values
27
+ raise StandardError.new("Requires hostname") unless hostname
26
28
  {
27
29
  :metadata => (base_metadata || {}).merge({
28
30
  :name => self.name,
29
31
  :group => self.group,
30
- :type => self.type
32
+ :type => self.type,
33
+ :hostname => self.hostname
31
34
  }),
32
35
  :display_options => self.display_options,
33
36
  :name => self.metric_id,
34
- :value => self.value
37
+ :values => self.values || {}
35
38
  }
36
39
  end
37
40
  end
@@ -8,7 +8,7 @@ module Neutrino
8
8
  def initialize(opts={})
9
9
  super(opts)
10
10
  configure
11
- # query
11
+ query
12
12
  end
13
13
 
14
14
  def self.execute_and_parse(command)
@@ -16,9 +16,16 @@ module Neutrino
16
16
  stdout.read.strip
17
17
  end
18
18
  result = {}
19
- output.split("\n").each do |line|
19
+ Log.debug("#{command} outputs #{output}")
20
+ output.to_s.split("\n").each do |line|
20
21
  whole_line, key, value = line.match(/(\S*) (.*)/).to_a
21
- key_parts = key.split(/\.|_/)
22
+ key = line.strip if key.nil? # Can be nil if no value is specified
23
+ key_parts = nil
24
+ if key.match("graph_")
25
+ key_parts = key.split(/_/)
26
+ else
27
+ key_parts = key.split(/\./)
28
+ end
22
29
  if key_parts.length == 2
23
30
  result[key_parts.first] ||= {}
24
31
  result[key_parts.first][key_parts.last] = value
@@ -26,6 +33,7 @@ module Neutrino
26
33
  result[key_parts.first] = value
27
34
  end
28
35
  end
36
+ Log.debug("#{command} output is parsed as #{result.inspect}")
29
37
  result
30
38
  end
31
39
 
@@ -44,14 +52,22 @@ module Neutrino
44
52
  self.base_metadata["group"] = plugin_configuration["graph"]["category"]
45
53
  self.base_metadata["type"] = plugin_configuration["graph"]["vlabel"]
46
54
  self.base_metadata["name"] = plugin_configuration["graph"]["title"]
55
+ self.name = plugin_configuration["graph"]["title"]
47
56
  end
48
57
  end
49
58
 
50
59
  def query
51
60
  plugin_query = MuninMetric.query_plugin(self.munin_plugin_path)
52
61
  begin
53
- self.value = plugin_query.to_a.first[1]["value"]
54
- rescue
62
+ values_hash = {}
63
+ plugin_query.to_a.each do |metric|
64
+ name = metric[0]
65
+ val = metric[1]["value"]
66
+ values_hash[name] = val.nil? ? nil : val.to_f
67
+ end
68
+ self.values = values_hash
69
+ rescue => e
70
+ Log.debug("Error querying munin: #{e}")
55
71
  end
56
72
  end
57
73
 
@@ -6,60 +6,46 @@ module Neutrino
6
6
 
7
7
  def self.record(metric)
8
8
  Log.info("Recording: #{metric.to_json}")
9
- HTTParty.post('http://neutrino2.heroku.com/record', :body => metric.to_json)
10
- # `curl --silent -X POST -H 'Content-Type: application/json' -d '#{metric.to_json}' http://neutrino2.heroku.com/record`
9
+ response = HTTParty.post('http://neutrino2.heroku.com/record', :body => metric.to_h)
10
+ Log.debug "Response: body=#{response.body} code=#{response.code} message=#{response.message} headers=#{response.headers.inspect}"
11
11
  end
12
12
 
13
13
  def self.get_metrics
14
14
  ms = [
15
- ShellMetric.new({
16
- :name => "CPU Steal",
17
- :command => "iostat | grep -A1 avg-cpu | tail -1 | awk '{print $5}'",
18
- :group => "system",
19
- :type => "CPU"
20
- }),
21
15
  ShellMetric.new({
22
16
  :name => "User CPU",
23
- :command => "iostat | grep -A1 avg-cpu | tail -1 | awk '{print $1}'",
17
+ :commands => {:user => "iostat | grep -A1 avg-cpu | tail -1 | awk '{print $1}'"},
24
18
  :group => "system",
25
19
  :type => "CPU",
26
20
  :display_options => {:min => 0, :max => 1}
27
21
  }),
28
22
  ShellMetric.new({
29
23
  :name => "Idle CPU",
30
- :command => "iostat | grep -A1 avg-cpu | tail -1 | awk '{print $6}'",
24
+ :commands => {:idle => "iostat | grep -A1 avg-cpu | tail -1 | awk '{print $6}'"},
31
25
  :group => "system",
32
26
  :type => "CPU",
33
27
  :display_options => {:min => 0, :max => 100}
34
28
  }),
35
29
  ShellMetric.new({
36
30
  :name => "Free Memory",
37
- :command => "cat /proc/meminfo | grep 'MemFree' | awk '{print $2}'",
31
+ :commands => {:free => "cat /proc/meminfo | grep 'MemFree' | awk '{print $2}'"},
38
32
  :group => "system",
39
33
  :type => 'memory'
40
34
  # :display_options => {:min => 0, :max => ShellMetric.execute("cat /proc/meminfo | grep 'MemTotal' | awk '{print $2}'")}
41
35
  }),
42
- ShellMetric.new({
43
- :name => "Load Avg (1m)",
44
- :command => "cat /proc/loadavg | awk '{print $1}'",
45
- :group => "system",
46
- :type => 'load'
47
- }),
48
- ShellMetric.new({
49
- :name => "Load Avg (5m)",
50
- :command => "cat /proc/loadavg | awk '{print $2}'",
51
- :group => "system",
52
- :type => 'load'
53
- }),
54
36
  ShellMetric.new({
55
37
  :name => "Load Avg (15m)",
56
- :command => "cat /proc/loadavg | awk '{print $3}'",
38
+ :commands => {
39
+ "1_min" => "cat /proc/loadavg | awk '{print $1}'",
40
+ "5_min" => "cat /proc/loadavg | awk '{print $2}'",
41
+ "15_min" => "cat /proc/loadavg | awk '{print $3}'",
42
+ },
57
43
  :group => "system",
58
44
  :type => 'load'
59
45
  }),
60
46
  ShellMetric.new({
61
47
  :name => "Process Count",
62
- :command => "ps aux | wc -l",
48
+ :commands => {:processes => "ps aux | wc -l"},
63
49
  :group => "system",
64
50
  :type => 'process'
65
51
  })
@@ -72,11 +58,7 @@ module Neutrino
72
58
  get_metrics.each do |m|
73
59
  m.hostname = `hostname`.strip
74
60
  m.base_metadata = Config.metadata
75
- begin
76
- Reporter.record(m)
77
- rescue StandardError => e
78
- Log.warn("Error running '#{m.name}': #{e}")
79
- end
61
+ Reporter.record(m)
80
62
  end
81
63
  end
82
64
  end
@@ -3,20 +3,28 @@ require 'open3'
3
3
  module Neutrino
4
4
  module Client
5
5
  class ShellMetric < Metric
6
- property :command
6
+ property :commands
7
+
8
+ def initialize(opts={})
9
+ super(opts)
10
+ query
11
+ end
7
12
 
8
13
  def self.execute(command)
9
14
  parsed_value = Open3.popen3(command) do |stdin, stdout, stderr, wait_thr|
10
15
  stdout.read.strip
11
16
  end
12
- raise StandardError.new("Could not parse a value from \"#{command}\". Got '#{parsed_value}'") if parsed_value.nil? || parsed_value == ""
17
+ Log.debug("'#{command}' outputs '#{parsed_value}'")
18
+ Log.warn("'#{command}' outputs '#{parsed_value}'") if parsed_value.nil? || parsed_value.empty?
13
19
  return parsed_value
14
20
  end
15
21
 
16
- def value
17
- v = ShellMetric.execute(self.command)
18
- Log.debug("#{self.command} returns '#{v}'")
19
- v
22
+ def query
23
+ values_hash = {}
24
+ self.commands.each_pair do |name, cmd|
25
+ values_hash[name] = ShellMetric.execute(cmd)
26
+ end
27
+ self.values = values_hash
20
28
  end
21
29
  end
22
30
  end
@@ -1,5 +1,5 @@
1
1
  module Neutrino
2
2
  module Client
3
- VERSION = "0.0.3"
3
+ VERSION = "0.0.5"
4
4
  end
5
5
  end
@@ -1,4 +1,4 @@
1
- require "neutrino/client"
1
+ require "lib/neutrino/client"
2
2
  require "test/unit"
3
3
 
4
4
  module Neutrino
@@ -1,4 +1,4 @@
1
- require "neutrino/client"
1
+ require "lib/neutrino/client"
2
2
  require "test/unit"
3
3
 
4
4
  module Neutrino
@@ -1,4 +1,4 @@
1
- require "neutrino/client"
1
+ require "lib/neutrino/client"
2
2
  require "test/unit"
3
3
  require 'mocha'
4
4
 
@@ -17,7 +17,7 @@ module Neutrino
17
17
  def test_metric_attributes
18
18
  attrs = {
19
19
  :name => "Load Avg (15m)",
20
- :value => 747,
20
+ :values => {:myval => 747},
21
21
  :group => "system",
22
22
  :type => 'load',
23
23
  :display_options => {:width => 100}
@@ -26,7 +26,8 @@ module Neutrino
26
26
  assert_equal metric.group, attrs[:group]
27
27
  assert_equal metric.type, attrs[:type]
28
28
  assert_equal metric.name, attrs[:name]
29
- assert_equal metric.value, attrs[:value]
29
+ assert_equal metric.values, attrs[:values]
30
+ assert_equal metric.values[:myval], attrs[:values][:myval]
30
31
  assert_equal metric.display_options, attrs[:display_options]
31
32
  end
32
33
 
@@ -51,16 +52,6 @@ module Neutrino
51
52
  assert_equal metric.metric_id, Digest::MD5.hexdigest("#{name}#{hostname}")
52
53
  end
53
54
 
54
- def test_metric_id_raises_without_hostname
55
- metric = Metric.new(:name => "a_metric")
56
- assert_raises(StandardError){ metric.metric_id }
57
- end
58
-
59
- def test_metric_id_raises_without_hostname
60
- metric = Metric.new(:hostname => "a_metric.com")
61
- assert_raises(StandardError){ metric.metric_id }
62
- end
63
-
64
55
  def test_to_json_calls_to_h
65
56
  metric = Metric.new(:hostname => "a_metric.com", :name => "asdf")
66
57
  metric.expects(:to_h)
@@ -70,7 +61,7 @@ module Neutrino
70
61
  def test_metric_to_h
71
62
  attrs = {
72
63
  :name => "Load Avg (15m)",
73
- :value => 0.11,
64
+ :values => {:bval => 0.11},
74
65
  :group => "system",
75
66
  :type => 'load',
76
67
  :display_options => {:width => 100}
@@ -84,10 +75,46 @@ module Neutrino
84
75
  assert_equal result[:metadata][:name], attrs[:name]
85
76
  assert_equal result[:metadata][:group], attrs[:group]
86
77
  assert_equal result[:metadata][:type], attrs[:type]
78
+ assert_equal result[:metadata][:hostname], metric.hostname
87
79
  assert_equal result[:display_options], attrs[:display_options]
88
- assert_equal result[:value], attrs[:value]
80
+ assert_equal result[:values][:bval], 0.11
89
81
  assert_equal result[:name], metric.metric_id
90
82
  end
83
+
84
+ def test_metric_to_h_raises_without_hostname
85
+ attrs = {
86
+ :name => "Load Avg (15m)",
87
+ :values => {:bval => 0.11},
88
+ :group => "system",
89
+ :type => 'load',
90
+ :display_options => {:width => 100}
91
+ }
92
+ metric = Metric.new(attrs)
93
+ assert_raises(StandardError){ metric.to_h }
94
+ end
95
+
96
+ def test_metric_to_h_raises_without_name
97
+ attrs = {
98
+ :values => {:bval => 0.11},
99
+ :group => "system",
100
+ :type => 'load',
101
+ :display_options => {:width => 100}
102
+ }
103
+ metric = Metric.new(attrs)
104
+ assert_raises(StandardError){ metric.to_h }
105
+ end
106
+
107
+ def test_metric_to_h_raises_without_values
108
+ attrs = {
109
+ :name => "Load Avg (15m)",
110
+ :group => "system",
111
+ :type => 'load',
112
+ :display_options => {:width => 100}
113
+ }
114
+ metric = Metric.new(attrs)
115
+ assert_raises(StandardError){ metric.to_h }
116
+ end
117
+
91
118
  end
92
119
  end
93
120
  end
@@ -1,4 +1,4 @@
1
- require "neutrino/client"
1
+ require "lib/neutrino/client"
2
2
  require "test/unit"
3
3
  require 'mocha'
4
4
 
@@ -11,6 +11,7 @@ module Neutrino
11
11
 
12
12
  def test_properties
13
13
  path = "/path/to/plugin"
14
+ Open3.stubs(:popen3)
14
15
  m = MuninMetric.new(:munin_plugin_path => path)
15
16
  assert_equal m.munin_plugin_path, path
16
17
  end
@@ -42,8 +43,9 @@ module Neutrino
42
43
  assert_equal m["load"]["value"], "0.17"
43
44
  end
44
45
 
45
- def test_configure
46
+ def test_configuring_sets_base_metadata
46
47
  path = "/some_plugin"
48
+ Open3.stubs(:popen3).with("#{path}")
47
49
  Open3.expects(:popen3).with("#{path} config").returns("graph_title Load average\ngraph_args --base 1000 -l 0\ngraph_vlabel load\ngraph_scale no\ngraph_category system\nload.label load\nload.warning 10\nload.critical 120\ngraph_info The load average of the machine describes how many processes are in the run-queue (scheduled to run \"immediately\").\nload.info Average load for the five minutes.\n")
48
50
  m = MuninMetric.new(:munin_plugin_path => path)
49
51
  assert_equal m.base_metadata["group"], "system"
@@ -51,13 +53,48 @@ module Neutrino
51
53
  assert_equal m.base_metadata["name"], "Load average"
52
54
  end
53
55
 
56
+ def test_can_handle_memory_output
57
+ path = "/some_plugin"
58
+ output = "swap_cache.value 0\nswap.value 0\n"
59
+ Open3.stubs(:popen3).with("#{path} config").returns("")
60
+ Open3.stubs(:popen3).with("#{path}").returns(output)
61
+ m = MuninMetric.new(:munin_plugin_path => path)
62
+ end
63
+
64
+ def test_can_handle_multiple_values
65
+ path = "/some_plugin"
66
+ output = "swap_cache.value 33\nswap.value 44\n"
67
+ Open3.stubs(:popen3).with("#{path} config").returns("")
68
+ Open3.stubs(:popen3).with("#{path}").returns(output)
69
+ m = MuninMetric.new(:munin_plugin_path => path)
70
+ assert_equal m.values["swap_cache"], 33
71
+ assert_equal m.values["swap"], 44
72
+ end
73
+
74
+ def test_can_handle_no_values
75
+ path = "/some_plugin"
76
+ output = "swap_cache.value\nswap.value 44\n"
77
+ Open3.stubs(:popen3).with("#{path} config").returns("")
78
+ Open3.stubs(:popen3).with("#{path}").returns(output)
79
+ m = MuninMetric.new(:munin_plugin_path => path)
80
+ assert_equal m.values["swap_cache"], nil
81
+ assert m.values.keys.include? "swap_cache"
82
+ end
83
+
84
+ def test_instanciation_configures_and_queries
85
+ path = "/some_plugin"
86
+ Open3.stubs(:popen3).with("#{path}")
87
+ Open3.expects(:popen3).with("#{path} config")
88
+ MuninMetric.new(:munin_plugin_path => path)
89
+ end
90
+
54
91
  def test_query
55
92
  path = "/some_plugin"
56
93
  Open3.expects(:popen3).with("#{path} config").returns("")
57
94
  Open3.expects(:popen3).with(path).returns("load.value 123\n")
58
95
  m = MuninMetric.new(:munin_plugin_path => path)
59
- m.query
60
- assert_equal m.value, "123"
96
+ assert m.values.keys.include? "load"
97
+ assert_equal m.values["load"], 123
61
98
  end
62
99
  end
63
100
  end
@@ -1,4 +1,4 @@
1
- require "neutrino/client"
1
+ require "lib/neutrino/client"
2
2
  require "test/unit"
3
3
  require 'mocha'
4
4
  require 'fakeweb'
@@ -12,6 +12,7 @@ module Neutrino
12
12
  ShellMetric.stubs(:execute).returns(3.14159)
13
13
 
14
14
  FakeWeb.allow_net_connect = false
15
+ FakeWeb.register_uri(:post, %r|neutrino2\.heroku\.com/|, :body => "{ok:1}")
15
16
  end
16
17
 
17
18
  def test_reporter_should_call_record_one_per_metric
@@ -20,17 +21,11 @@ module Neutrino
20
21
  Reporter.report
21
22
  end
22
23
 
23
- def test_reporter_swallows_errors_and_logs_warnings
24
- Open3.stubs(:popen3).returns('')
25
- metrics = Reporter.get_metrics
26
- Log.expects(:warn).times(metrics.length)
27
- Reporter.report
28
- end
29
-
30
24
  def test_reporter_adds_munin_plugins
25
+ dummy_metric = Metric.new(:name => "a", :hostname => 'asdf', :values => {:a => 1})
31
26
  Dir.expects(:glob).with("/somedir/*").returns(["/path1", "/path2"])
32
- MuninMetric.expects(:new).with(:munin_plugin_path => "/path1").returns(Metric.new)
33
- MuninMetric.expects(:new).with(:munin_plugin_path => "/path2").returns(Metric.new)
27
+ MuninMetric.expects(:new).with(:munin_plugin_path => "/path1").returns(dummy_metric)
28
+ MuninMetric.expects(:new).with(:munin_plugin_path => "/path2").returns(dummy_metric)
34
29
  Config.munin_plugin_globs "/somedir/*"
35
30
  Reporter.report
36
31
  end
@@ -1,4 +1,4 @@
1
- require "neutrino/client"
1
+ require "lib/neutrino/client"
2
2
  require "test/unit"
3
3
  require 'mocha'
4
4
 
@@ -9,22 +9,43 @@ module Neutrino
9
9
  Config.defaults!
10
10
  end
11
11
 
12
+ def test_initialization_calls_query
13
+ ShellMetric.expects(:execute).with("somecmd").returns(100)
14
+ m = ShellMetric.new(:commands => {:myval => "somecmd"})
15
+ end
16
+
12
17
  def test_execute_calculates_value
13
18
  cmd = "ps aux | wc -l"
14
- m = ShellMetric.new(:command => cmd)
15
19
  ShellMetric.expects(:execute).with(cmd)
16
- m.value
20
+ m = ShellMetric.new(:commands => {:myval => cmd})
17
21
  end
18
22
 
19
- def test_executes_command
23
+ def test_creates_values_hash
24
+ ShellMetric.stubs(:execute).with("somecmd").returns(100)
25
+ ShellMetric.stubs(:execute).with("othercmd").returns(150)
26
+ m = ShellMetric.new(:commands => {:myval => "somecmd", :bval => "othercmd"})
27
+ assert_equal m.values[:myval], 100
28
+ assert_equal m.values[:bval], 150
29
+ end
30
+
31
+ def test_reporter_logs_warnings_for_empty_output
32
+ cmd = "ps aux | wc -l"
33
+ Open3.stubs(:popen3).with(cmd).returns("")
34
+ Log.expects(:warn)
35
+ ShellMetric.execute(cmd)
36
+ end
37
+
38
+ def test_reporter_logs_debugs
20
39
  cmd = "ps aux | wc -l"
21
- Open3.expects(:popen3).with(cmd).returns(100)
40
+ Open3.stubs(:popen3).with(cmd).returns("100")
41
+ Log.expects(:debug)
22
42
  ShellMetric.execute(cmd)
23
43
  end
24
44
 
25
- def test_execute_raises_error_without_value
26
- Open3.stubs(:popen3).returns('')
27
- assert_raises(StandardError){ShellMetric.execute("some bogus command")}
45
+ def test_executes_command
46
+ cmd = "ps aux | wc -l"
47
+ Open3.expects(:popen3).with(cmd).returns("100")
48
+ ShellMetric.execute(cmd)
28
49
  end
29
50
  end
30
51
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: neutrino_client
3
3
  version: !ruby/object:Gem::Version
4
- hash: 25
4
+ hash: 21
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 3
10
- version: 0.0.3
9
+ - 5
10
+ version: 0.0.5
11
11
  platform: ruby
12
12
  authors:
13
13
  - Nick Stielau
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-02-14 00:00:00 -08:00
18
+ date: 2011-02-25 00:00:00 -08:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency