neutrino_client 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source :gemcutter
2
+
3
+ # Specify your gem's dependencies in neutrino_client.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,38 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ neutrino_client (0.0.1)
5
+ hashie (>= 1.0.0)
6
+ httparty (>= 0.5.3)
7
+ json_pure (>= 1.4.6)
8
+ mixlib-cli (>= 1.2.0)
9
+ mixlib-config (>= 1.1.2)
10
+
11
+ GEM
12
+ remote: http://rubygems.org/
13
+ specs:
14
+ crack (0.1.8)
15
+ fakeweb (1.3.0)
16
+ hashie (1.0.0)
17
+ httparty (0.7.3)
18
+ crack (= 0.1.8)
19
+ json_pure (1.4.6)
20
+ mixlib-cli (1.2.0)
21
+ mixlib-config (1.1.2)
22
+ mocha (0.9.11)
23
+ rake
24
+ rake (0.8.7)
25
+
26
+ PLATFORMS
27
+ ruby
28
+
29
+ DEPENDENCIES
30
+ bundler (>= 1.0.0)
31
+ fakeweb (>= 1.3.0)
32
+ hashie (>= 1.0.0)
33
+ httparty (>= 0.5.3)
34
+ json_pure (>= 1.4.6)
35
+ mixlib-cli (>= 1.2.0)
36
+ mixlib-config (>= 1.1.2)
37
+ mocha (>= 0.9.11)
38
+ neutrino_client!
data/README ADDED
File without changes
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
data/TODO ADDED
@@ -0,0 +1 @@
1
+ Send with httparty, not curl
data/bin/neutrino ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'neutrino/client'
4
+
5
+ Neutrino::Client::CLI.new.run
6
+ Neutrino::Client::Reporter.report
@@ -0,0 +1,34 @@
1
+ require 'mixlib/cli'
2
+
3
+ module Neutrino
4
+ module Client
5
+ class CLI
6
+ include Mixlib::CLI
7
+
8
+ option :log_level,
9
+ :short => "-l LEVEL",
10
+ :long => "--log_level LEVEL",
11
+ :description => "Set the log level (debug, info, warn, error, fatal)",
12
+ :proc => Proc.new { |l| l.to_sym }
13
+
14
+ option :help,
15
+ :short => "-h",
16
+ :long => "--help",
17
+ :description => "Show this message",
18
+ :on => :tail,
19
+ :boolean => true,
20
+ :show_options => true,
21
+ :exit => 0
22
+
23
+ def run(argv=ARGV)
24
+ parse_options(argv)
25
+ # Load config from file
26
+ Config.from_file(Config.config_file) if File.exist?(Config.config_file)
27
+ # Overrides from command-line
28
+ Config.merge!(config)
29
+
30
+ Log.level = Neutrino::Client::Config.log_level
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,12 @@
1
+ require 'neutrino/cli'
2
+ require 'neutrino/config'
3
+ require 'neutrino/log'
4
+ require 'neutrino/metric'
5
+ require 'neutrino/reporter'
6
+ require 'neutrino/shell_metric'
7
+ require 'json'
8
+
9
+ module Neutrino
10
+ module Client
11
+ end
12
+ end
@@ -0,0 +1,22 @@
1
+ require 'mixlib/config'
2
+
3
+ module Neutrino
4
+ module Client
5
+ class Config
6
+ extend(Mixlib::Config)
7
+
8
+ metadata {}
9
+
10
+ def self.defaults!
11
+ self.configuration = {}
12
+ configure do |c|
13
+ c[:metadata] = {}
14
+ end
15
+ log_level :warn
16
+ config_file "/etc/neutrino.rb"
17
+ end
18
+
19
+ Config.defaults!
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,9 @@
1
+ require 'mixlib/log'
2
+
3
+ module Neutrino
4
+ module Client
5
+ class Log
6
+ extend Mixlib::Log
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,39 @@
1
+ require 'hashie'
2
+ require 'digest/md5'
3
+
4
+ module Neutrino
5
+ module Client
6
+ class Metric < Hashie::Dash
7
+ property :hostname
8
+ property :base_metadata
9
+
10
+ property :group
11
+ property :type
12
+ property :name
13
+ property :value
14
+ property :display_options
15
+
16
+ def metric_id
17
+ raise StandardError.new("Requires name and hostname") unless name && hostname
18
+ Digest::MD5.hexdigest("#{name}#{hostname}")
19
+ end
20
+
21
+ def to_json
22
+ to_h.to_json
23
+ end
24
+
25
+ def to_h
26
+ {
27
+ :metadata => base_metadata.merge({
28
+ :name => self.name,
29
+ :group => self.group,
30
+ :type => self.type
31
+ }),
32
+ :display_options => self.display_options,
33
+ :name => self.metric_id,
34
+ :value => self.value
35
+ }
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,82 @@
1
+ require 'httparty'
2
+
3
+ module Neutrino
4
+ module Client
5
+ class Reporter
6
+
7
+ def self.record(metric)
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`
11
+ end
12
+
13
+ def self.get_metrics
14
+ [
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
+ ShellMetric.new({
22
+ :name => "User CPU",
23
+ :command => "iostat | grep -A1 avg-cpu | tail -1 | awk '{print $1}'",
24
+ :group => "system",
25
+ :type => "CPU",
26
+ :display_options => {:min => 0, :max => 1}
27
+ }),
28
+ ShellMetric.new({
29
+ :name => "Idle CPU",
30
+ :command => "iostat | grep -A1 avg-cpu | tail -1 | awk '{print $6}'",
31
+ :group => "system",
32
+ :type => "CPU",
33
+ :display_options => {:min => 0, :max => 100}
34
+ }),
35
+ ShellMetric.new({
36
+ :name => "Free Memory",
37
+ :command => "cat /proc/meminfo | grep 'MemFree' | awk '{print $2}'",
38
+ :group => "system",
39
+ :type => 'memory'
40
+ # :display_options => {:min => 0, :max => ShellMetric.execute("cat /proc/meminfo | grep 'MemTotal' | awk '{print $2}'")}
41
+ }),
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
+ ShellMetric.new({
55
+ :name => "Load Avg (15m)",
56
+ :command => "cat /proc/loadavg | awk '{print $3}'",
57
+ :group => "system",
58
+ :type => 'load'
59
+ }),
60
+ ShellMetric.new({
61
+ :name => "Process Count",
62
+ :command => "ps aux | wc -l",
63
+ :group => "system",
64
+ :type => 'process'
65
+ })
66
+ ]
67
+ end
68
+
69
+ def self.report
70
+ get_metrics.each do |m|
71
+ m.hostname = `hostname`.strip
72
+ m.base_metadata = Config.metadata
73
+ begin
74
+ Reporter.record(m)
75
+ rescue StandardError => e
76
+ Log.warn("Error running '#{m.name}': #{e}")
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,23 @@
1
+ require 'open3'
2
+
3
+ module Neutrino
4
+ module Client
5
+ class ShellMetric < Metric
6
+ property :command
7
+
8
+ def self.execute(command)
9
+ parsed_value = Open3.popen3(command) do |stdin, stdout, stderr, wait_thr|
10
+ stdout.read.strip
11
+ end
12
+ raise StandardError.new("Could not parse a value from \"#{command}\". Got '#{parsed_value}'") if parsed_value.nil? || parsed_value == ""
13
+ return parsed_value
14
+ end
15
+
16
+ def value
17
+ v = ShellMetric.execute(self.command)
18
+ Log.debug("#{self.command} returns '#{v}'")
19
+ v
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,5 @@
1
+ module Neutrino
2
+ module Client
3
+ VERSION = "0.0.2"
4
+ end
5
+ end
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path("../lib/neutrino/version", __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "neutrino_client"
6
+ s.version = Neutrino::Client::VERSION
7
+ s.platform = Gem::Platform::RUBY
8
+ s.authors = ["Nick Stielau"]
9
+ s.email = ["nick.stielau+neutrino@gmail.com"]
10
+ s.homepage = "http://rubygems.org/gems/neutrino_client"
11
+ s.summary = "A client for sending metrics to Neutrino."
12
+ s.description = "A client for sending metrics to Neutrino."
13
+
14
+ s.required_rubygems_version = ">= 1.3.6"
15
+ s.rubyforge_project = "neutrino_client"
16
+
17
+ s.add_development_dependency "bundler", ">= 1.0.0"
18
+ s.add_development_dependency "mocha", ">= 0.9.11"
19
+ s.add_development_dependency "fakeweb", ">= 1.3.0"
20
+
21
+ s.add_dependency "mixlib-config", ">= 1.1.2"
22
+ s.add_dependency "mixlib-cli", ">= 1.2.0"
23
+ s.add_dependency "json_pure", ">= 1.4.6"
24
+ s.add_dependency "hashie", ">= 1.0.0"
25
+ s.add_dependency "httparty", ">= 0.5.3"
26
+
27
+ s.files = `git ls-files`.split("\n")
28
+ s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
29
+ s.require_path = 'lib'
30
+ end
data/test/cli_test.rb ADDED
@@ -0,0 +1,18 @@
1
+ require "neutrino/client"
2
+ require "test/unit"
3
+
4
+ module Neutrino
5
+ module Client
6
+ class TestCLI < Test::Unit::TestCase
7
+ def setup
8
+ Config.defaults!
9
+ @cli = Neutrino::Client::CLI.new
10
+ end
11
+
12
+ def test_cli_will_set_log_level
13
+ @cli.run(['-l', 'error'])
14
+ assert_equal(:error, Config.log_level)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,24 @@
1
+ require "neutrino/client"
2
+ require "test/unit"
3
+
4
+ module Neutrino
5
+ module Client
6
+ class TestConfig < Test::Unit::TestCase
7
+ def setup
8
+ Config.defaults!
9
+ end
10
+
11
+ def test_log_level_defaults_to_info
12
+ assert_equal(:warn, Config.log_level)
13
+ end
14
+
15
+ def test_metadata_defaults_to_empty_hash
16
+ assert_equal({}, Config.metadata)
17
+ end
18
+
19
+ def test_default_config_file
20
+ assert_equal("/etc/neutrino.rb", Config.config_file)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,93 @@
1
+ require "neutrino/client"
2
+ require "test/unit"
3
+ require 'mocha'
4
+
5
+ module Neutrino
6
+ module Client
7
+ class TestMetric < Test::Unit::TestCase
8
+ def setup
9
+ Config.defaults!
10
+ end
11
+
12
+ def test_metric_instatiation
13
+ metric = Metric.new
14
+ assert metric
15
+ end
16
+
17
+ def test_metric_attributes
18
+ attrs = {
19
+ :name => "Load Avg (15m)",
20
+ :value => 747,
21
+ :group => "system",
22
+ :type => 'load',
23
+ :display_options => {:width => 100}
24
+ }
25
+ metric = Metric.new(attrs)
26
+ assert_equal metric.group, attrs[:group]
27
+ assert_equal metric.type, attrs[:type]
28
+ assert_equal metric.name, attrs[:name]
29
+ assert_equal metric.value, attrs[:value]
30
+ assert_equal metric.display_options, attrs[:display_options]
31
+ end
32
+
33
+ def test_can_set_hostname
34
+ hostname = "some_hostname"
35
+ metric = Metric.new
36
+ metric.hostname = hostname
37
+ assert_equal metric.hostname, hostname
38
+ end
39
+
40
+ def test_metric_class_base_metadata
41
+ base_metadata = {"some_hostname" => "true"}
42
+ metric = Metric.new
43
+ metric.base_metadata = base_metadata
44
+ assert_equal metric.base_metadata, base_metadata
45
+ end
46
+
47
+ def test_metric_id
48
+ hostname = "panda.com"
49
+ name = "a_metric"
50
+ metric = Metric.new(:hostname => hostname, :name => name)
51
+ assert_equal metric.metric_id, Digest::MD5.hexdigest("#{name}#{hostname}")
52
+ end
53
+
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
+ def test_to_json_calls_to_h
65
+ metric = Metric.new(:hostname => "a_metric.com", :name => "asdf")
66
+ metric.expects(:to_h)
67
+ metric.to_json
68
+ end
69
+
70
+ def test_metric_to_h
71
+ attrs = {
72
+ :name => "Load Avg (15m)",
73
+ :value => 0.11,
74
+ :group => "system",
75
+ :type => 'load',
76
+ :display_options => {:width => 100}
77
+ }
78
+ metric = Metric.new(attrs)
79
+ metric.hostname = "panda.com"
80
+ metric.base_metadata = {:datacenter => "EC2"}
81
+ result = metric.to_h
82
+ assert_not_nil result[:metadata]
83
+ assert_equal result[:metadata][:datacenter], "EC2"
84
+ assert_equal result[:metadata][:name], attrs[:name]
85
+ assert_equal result[:metadata][:group], attrs[:group]
86
+ assert_equal result[:metadata][:type], attrs[:type]
87
+ assert_equal result[:display_options], attrs[:display_options]
88
+ assert_equal result[:value], attrs[:value]
89
+ assert_equal result[:name], metric.metric_id
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,31 @@
1
+ require "neutrino/client"
2
+ require "test/unit"
3
+ require 'mocha'
4
+ require 'fakeweb'
5
+
6
+ module Neutrino
7
+ module Client
8
+ class TestReporter < Test::Unit::TestCase
9
+ def setup
10
+ Config.defaults!
11
+ Config[:metadata] = {:datacenter => "EC2"}
12
+ ShellMetric.stubs(:execute).returns(3.14159)
13
+
14
+ FakeWeb.allow_net_connect = false
15
+ end
16
+
17
+ def test_reporter_should_call_record_one_per_metric
18
+ metrics = Reporter.get_metrics
19
+ Reporter.expects(:record).times(metrics.length)
20
+ Reporter.report
21
+ end
22
+
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
+ end
30
+ end
31
+ end
@@ -0,0 +1,31 @@
1
+ require "neutrino/client"
2
+ require "test/unit"
3
+ require 'mocha'
4
+
5
+ module Neutrino
6
+ module Client
7
+ class TestShellMetric < Test::Unit::TestCase
8
+ def setup
9
+ Config.defaults!
10
+ end
11
+
12
+ def test_execute_calculates_value
13
+ cmd = "ps aux | wc -l"
14
+ m = ShellMetric.new(:command => cmd)
15
+ ShellMetric.expects(:execute).with(cmd)
16
+ m.execute
17
+ end
18
+
19
+ def test_executes_command
20
+ cmd = "ps aux | wc -l"
21
+ Open3.expects(:popen3).with(cmd).returns(100)
22
+ ShellMetric.execute(cmd)
23
+ end
24
+
25
+ def test_execute_raises_error_without_value
26
+ Open3.stubs(:popen3).returns('')
27
+ assert_raises(StandardError){ShellMetric.execute("some bogus command")}
28
+ end
29
+ end
30
+ end
31
+ end
metadata ADDED
@@ -0,0 +1,217 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: neutrino_client
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 2
10
+ version: 0.0.2
11
+ platform: ruby
12
+ authors:
13
+ - Nick Stielau
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-02-11 00:00:00 -08:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: bundler
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 23
30
+ segments:
31
+ - 1
32
+ - 0
33
+ - 0
34
+ version: 1.0.0
35
+ type: :development
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: mocha
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 45
46
+ segments:
47
+ - 0
48
+ - 9
49
+ - 11
50
+ version: 0.9.11
51
+ type: :development
52
+ version_requirements: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ name: fakeweb
55
+ prerelease: false
56
+ requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ hash: 27
62
+ segments:
63
+ - 1
64
+ - 3
65
+ - 0
66
+ version: 1.3.0
67
+ type: :development
68
+ version_requirements: *id003
69
+ - !ruby/object:Gem::Dependency
70
+ name: mixlib-config
71
+ prerelease: false
72
+ requirement: &id004 !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ hash: 23
78
+ segments:
79
+ - 1
80
+ - 1
81
+ - 2
82
+ version: 1.1.2
83
+ type: :runtime
84
+ version_requirements: *id004
85
+ - !ruby/object:Gem::Dependency
86
+ name: mixlib-cli
87
+ prerelease: false
88
+ requirement: &id005 !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ hash: 31
94
+ segments:
95
+ - 1
96
+ - 2
97
+ - 0
98
+ version: 1.2.0
99
+ type: :runtime
100
+ version_requirements: *id005
101
+ - !ruby/object:Gem::Dependency
102
+ name: json_pure
103
+ prerelease: false
104
+ requirement: &id006 !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ hash: 11
110
+ segments:
111
+ - 1
112
+ - 4
113
+ - 6
114
+ version: 1.4.6
115
+ type: :runtime
116
+ version_requirements: *id006
117
+ - !ruby/object:Gem::Dependency
118
+ name: hashie
119
+ prerelease: false
120
+ requirement: &id007 !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ hash: 23
126
+ segments:
127
+ - 1
128
+ - 0
129
+ - 0
130
+ version: 1.0.0
131
+ type: :runtime
132
+ version_requirements: *id007
133
+ - !ruby/object:Gem::Dependency
134
+ name: httparty
135
+ prerelease: false
136
+ requirement: &id008 !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ">="
140
+ - !ruby/object:Gem::Version
141
+ hash: 13
142
+ segments:
143
+ - 0
144
+ - 5
145
+ - 3
146
+ version: 0.5.3
147
+ type: :runtime
148
+ version_requirements: *id008
149
+ description: A client for sending metrics to Neutrino.
150
+ email:
151
+ - nick.stielau+neutrino@gmail.com
152
+ executables:
153
+ - neutrino
154
+ extensions: []
155
+
156
+ extra_rdoc_files: []
157
+
158
+ files:
159
+ - .gitignore
160
+ - Gemfile
161
+ - Gemfile.lock
162
+ - README
163
+ - Rakefile
164
+ - TODO
165
+ - bin/neutrino
166
+ - lib/neutrino/cli.rb
167
+ - lib/neutrino/client.rb
168
+ - lib/neutrino/config.rb
169
+ - lib/neutrino/log.rb
170
+ - lib/neutrino/metric.rb
171
+ - lib/neutrino/reporter.rb
172
+ - lib/neutrino/shell_metric.rb
173
+ - lib/neutrino/version.rb
174
+ - neutrino_client.gemspec
175
+ - test/cli_test.rb
176
+ - test/config_test.rb
177
+ - test/metric_test.rb
178
+ - test/reporter_test.rb
179
+ - test/shell_metric_test.rb
180
+ has_rdoc: true
181
+ homepage: http://rubygems.org/gems/neutrino_client
182
+ licenses: []
183
+
184
+ post_install_message:
185
+ rdoc_options: []
186
+
187
+ require_paths:
188
+ - lib
189
+ required_ruby_version: !ruby/object:Gem::Requirement
190
+ none: false
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ hash: 3
195
+ segments:
196
+ - 0
197
+ version: "0"
198
+ required_rubygems_version: !ruby/object:Gem::Requirement
199
+ none: false
200
+ requirements:
201
+ - - ">="
202
+ - !ruby/object:Gem::Version
203
+ hash: 23
204
+ segments:
205
+ - 1
206
+ - 3
207
+ - 6
208
+ version: 1.3.6
209
+ requirements: []
210
+
211
+ rubyforge_project: neutrino_client
212
+ rubygems_version: 1.3.7
213
+ signing_key:
214
+ specification_version: 3
215
+ summary: A client for sending metrics to Neutrino.
216
+ test_files: []
217
+