instrumental_agent 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour --format Fuubar
data/Guardfile CHANGED
@@ -1,4 +1,4 @@
1
- guard 'rspec', :version => 2 do
1
+ guard 'rspec', :version => 2, :cli => '--format Fuubar' do
2
2
  watch(%r{^spec/.+_spec\.rb$})
3
3
  watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
4
4
  watch(%r{spec/(spec_helper|test_server).rb}) { "spec/" }
@@ -1,225 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'rubygems'
4
- $: << File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
5
- require 'instrumental_agent'
6
-
7
-
8
- class SystemInspector
9
- TYPES = [:gauges, :incrementors]
10
- attr_accessor *TYPES
11
-
12
- def initialize
13
- @gauges = {}
14
- @incrementors = {}
15
- @platform =
16
- case RUBY_PLATFORM
17
- when /linux/
18
- Linux
19
- when /darwin/
20
- OSX
21
- else
22
- raise "unsupported OS"
23
- end
24
- end
25
-
26
- def load_all
27
- load @platform.load_cpu
28
- load @platform.load_memory
29
- load @platform.load_disks
30
- end
31
-
32
- def load(stats)
33
- @gauges.merge!(stats[:gauges] || {})
34
- end
35
-
36
- module OSX
37
- def self.load_cpu
38
- { :gauges => top }
39
- end
40
-
41
- def self.top
42
- lines = []
43
- processes = date = load = cpu = nil
44
- IO.popen('top -l 1 -n 0') do |top|
45
- processes = top.gets.split(': ')[1]
46
- date = top.gets
47
- load = top.gets.split(': ')[1]
48
- cpu = top.gets.split(': ')[1]
49
- end
50
-
51
- user, system, idle = cpu.split(", ").map { |v| v.to_f }
52
- load1, load5, load15 = load.split(", ").map { |v| v.to_f }
53
- total, running, stuck, sleeping, threads = processes.split(", ").map { |v| v.to_i }
54
-
55
- {
56
- 'cpu.user' => user,
57
- 'cpu.system' => system,
58
- 'cpu.idle' => idle,
59
- 'load.1min' => load1,
60
- 'load.5min' => load5,
61
- 'load.15min' => load15,
62
- 'processes.total' => total,
63
- 'processes.running' => running,
64
- 'processes.stuck' => stuck,
65
- 'processes.sleeping' => sleeping,
66
- 'threads' => threads,
67
- }
68
- end
69
-
70
- def self.load_memory
71
- # TODO: swap
72
- { :gauges => vm_stat }
73
- end
74
-
75
- def self.vm_stat
76
- header, *rows = `vm_stat`.split("\n")
77
- page_size = header.match(/page size of (\d+) bytes/)[1].to_i
78
- sections = ["free", "active", "inactive", "wired", "speculative", "wired down"]
79
- output = {}
80
- total = 0.0
81
- rows.each do |row|
82
- if match = row.match(/Pages (.*):\s+(\d+)\./)
83
- section, value = match[1, 2]
84
- if sections.include?(section)
85
- value = value.to_f * page_size / 1024 / 1024
86
- output["memory.#{section.gsub(' ', '_')}_mb"] = value
87
- total += value
88
- end
89
- end
90
- end
91
- output["memory.free_percent"] = output["memory.free_mb"] / total * 100 # TODO: verify
92
- output
93
- end
94
-
95
- def self.load_disks
96
- { :gauges => df }
97
- end
98
-
99
- def self.df
100
- output = {}
101
- `df -k`.split("\n").grep(%r{^/dev/}).each do |line|
102
- device, total, used, available, capacity, mount = line.split(/\s+/)
103
- names = [File.basename(device)]
104
- names << 'root' if mount == '/'
105
- names.each do |name|
106
- output["disk.#{name}.total_mb"] = total.to_f / 1024
107
- output["disk.#{name}.used_mb"] = used.to_f / 1024
108
- output["disk.#{name}.available_mb"] = available.to_f / 1024
109
- output["disk.#{name}.available_percent"] = available.to_f / total.to_f * 100
110
- end
111
- end
112
- output
113
- end
114
-
115
- def self.netstat(interface = 'en1')
116
- # mostly functional network io stats
117
- headers, *lines = `netstat -ibI #{interface}`.split("\n").map { |l| l.split(/\s+/) } # FIXME: vulnerability?
118
- headers = headers.map { |h| h.downcase }
119
- lines.each do |line|
120
- if !line[3].include?(':')
121
- return Hash[headers.zip(line)]
122
- end
123
- end
124
- end
125
- end
126
-
127
- module Linux
128
- def self.load_cpu
129
- output = { :gauges => {} }
130
- output[:gauges].merge!(cpu)
131
- output[:gauges].merge!(loadavg)
132
- output
133
- end
134
-
135
- def self.cpu
136
- cpu, user, nice, system, idle, iowait = `cat /proc/stat | grep cpu[^0-9]`.chomp.split(/\s+/)
137
- total = user.to_i + system.to_i + idle.to_i + iowait.to_i
138
- {
139
- 'cpu.user' => (user.to_f / total) * 100,
140
- 'cpu.system' => (system.to_f / total) * 100,
141
- 'cpu.idle' => (idle.to_f / total) * 100,
142
- 'cpu.iowait' => (iowait.to_f / total) * 100,
143
- }
144
- end
145
-
146
- def self.loadavg
147
- min_1, min_5, min_15 = `cat /proc/loadavg`.split(/\s+/)
148
- {
149
- 'load.1min' => min_1.to_f,
150
- 'load.5min' => min_5.to_f,
151
- 'load.15min' => min_15.to_f,
152
- }
153
- end
154
-
155
- def self.load_memory
156
- output = { :gauges => {} }
157
- output[:gauges].merge!(memory)
158
- output[:gauges].merge!(swap)
159
- output
160
- end
161
-
162
- def self.memory
163
- _, total, used, free, shared, buffers, cached = `free -k -o | grep Mem`.chomp.split(/\s+/)
164
- {
165
- 'memory.used_mb' => used.to_f / 1024,
166
- 'memory.free_mb' => free.to_f / 1024,
167
- 'memory.buffers_mb' => buffers.to_f / 1024,
168
- 'memory.cached_mb' => cached.to_f / 1024,
169
- 'memory.free_percent' => (free.to_f / total.to_f) * 100,
170
- }
171
- end
172
-
173
- def self.swap
174
- _, total, used, free = `free -k -o | grep Swap`.chomp.split(/\s+/)
175
- {
176
- 'swap.used_mb' => used.to_f / 1024,
177
- 'swap.free_mb' => free.to_f / 1024,
178
- 'swap.free_percent' => (free.to_f / total.to_f) * 100,
179
- }
180
- end
181
-
182
- def self.load_disks
183
- { :gauges => disks }
184
- end
185
-
186
- def self.disks
187
- output = {}
188
- `df -Pk`.split("\n").grep(%r{^/dev/}).each do |line|
189
- device, total, used, available, capacity, mount = line.split(/\s+/)
190
- names = [File.basename(device)]
191
- names << 'root' if mount == '/'
192
- names.each do |name|
193
- output["disk.#{name}.total_mb"] = total.to_f / 1024
194
- output["disk.#{name}.used_mb"] = used.to_f / 1024
195
- output["disk.#{name}.available_mb"] = available.to_f / 1024
196
- output["disk.#{name}.available_percent"] = available.to_f / total.to_f * 100
197
- end
198
- end
199
- output
200
- end
201
- end
202
- end
203
-
204
- # TODO: utilization
205
-
206
- token, collector = *ARGV
207
- unless token
208
- puts "Usage: #{$0} <token> [collector]"
209
- exit 1
210
- end
211
- I = Instrumental::Agent.new(token, :collector => collector)
212
-
213
- host = `hostname`.chomp
214
-
215
- puts "Collecting stats under the hostname: #{host}"
216
-
217
- loop do
218
- inspector = SystemInspector.new
219
- inspector.load_all
220
- inspector.gauges.each do |stat, value|
221
- I.gauge("#{host}.#{stat}", value)
222
- end
223
- # I.increment("#{host}.#{stat}", delta)
224
- sleep 10
225
- end
3
+ puts '***********************************'
4
+ puts '*** Moved to instrumental_tools ***'
5
+ puts '***********************************'
6
+ puts "\ngem install instrumental_tools\n"
7
+ exit 1
@@ -20,4 +20,5 @@ Gem::Specification.new do |s|
20
20
  s.add_development_dependency(%q<guard-rspec>, [">= 0"])
21
21
  s.add_development_dependency(%q<growl_notify>, [">= 0"])
22
22
  s.add_development_dependency(%q<rb-fsevent>, [">= 0"])
23
+ s.add_development_dependency(%q<fuubar>, [">= 0"])
23
24
  end
@@ -101,24 +101,35 @@ module Instrumental
101
101
  @socket && !@socket.closed?
102
102
  end
103
103
 
104
+ def logger=(logger)
105
+ @logger = logger
106
+ end
107
+
104
108
  def logger
105
- self.class.logger
109
+ @logger ||= self.class.logger
106
110
  end
107
111
 
108
112
  private
109
113
 
110
114
  def valid?(metric, value, time)
111
- if metric !~ /^([\d\w\-_]+\.)*[\d\w\-_]+$/i
112
- increment 'agent.invalid_metric'
113
- logger.warn "Invalid metric #{metric}"
114
- return false
115
- end
116
- if value.to_s !~ /^\d+(\.\d+)?$/
117
- increment 'agent.invalid_value'
118
- logger.warn "Invalid value #{value.inspect} for #{metric}"
119
- return false
120
- end
121
- true
115
+ valid_metric = metric =~ /^([\d\w\-_]+\.)*[\d\w\-_]+$/i
116
+ valid_value = value.to_s =~ /^-?\d+(\.\d+)?$/
117
+
118
+ return true if valid_metric && valid_value
119
+
120
+ report_invalid_metric(metric) unless valid_metric
121
+ report_invalid_value(metric, value) unless valid_value
122
+ false
123
+ end
124
+
125
+ def report_invalid_metric(metric)
126
+ increment "agent.invalid_metric"
127
+ logger.warn "Invalid metric #{metric}"
128
+ end
129
+
130
+ def report_invalid_value(metric, value)
131
+ increment "agent.invalid_value"
132
+ logger.warn "Invalid value #{value.inspect} for #{metric}"
122
133
  end
123
134
 
124
135
  def report_exception(e)
@@ -1,3 +1,3 @@
1
1
  module Instrumental
2
- VERSION = "0.4.0"
2
+ VERSION = "0.5.0"
3
3
  end
data/spec/agent_spec.rb CHANGED
@@ -180,4 +180,39 @@ describe Instrumental::Agent, "enabled" do
180
180
  end
181
181
  @agent.increment("test").should be_nil
182
182
  end
183
+
184
+ it "should track invalid metrics" do
185
+ @agent.logger.should_receive(:warn).with(/%%/)
186
+ @agent.increment(' %% .!#@$%^&*', 1, 1)
187
+ wait
188
+ @server.commands.join("\n").should include("increment agent.invalid_metric")
189
+ end
190
+
191
+ it "should allow reasonable metric names" do
192
+ @agent.increment('a')
193
+ @agent.increment('a.b')
194
+ @agent.increment('hello.world')
195
+ @agent.increment('ThisIsATest.Of.The.Emergency.Broadcast.System.12345')
196
+ wait
197
+ @server.commands.join("\n").should_not include("increment agent.invalid_metric")
198
+ end
199
+
200
+ it "should track invalid values" do
201
+ @agent.logger.should_receive(:warn).with(/hello.*testington/)
202
+ @agent.increment('testington', 'hello')
203
+ wait
204
+ @server.commands.join("\n").should include("increment agent.invalid_value")
205
+ end
206
+
207
+ it "should allow reasonable values" do
208
+ @agent.increment('a', -333.333)
209
+ @agent.increment('a', -2.2)
210
+ @agent.increment('a', -1)
211
+ @agent.increment('a', 0)
212
+ @agent.increment('a', 1)
213
+ @agent.increment('a', 2.2)
214
+ @agent.increment('a', 333.333)
215
+ wait
216
+ @server.commands.join("\n").should_not include("increment agent.invalid_value")
217
+ end
183
218
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: instrumental_agent
3
3
  version: !ruby/object:Gem::Version
4
- hash: 15
5
- prerelease:
4
+ prerelease: false
6
5
  segments:
7
6
  - 0
8
- - 4
7
+ - 5
9
8
  - 0
10
- version: 0.4.0
9
+ segments_generated: true
10
+ version: 0.5.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Elijah Miller
@@ -17,94 +17,101 @@ autorequire:
17
17
  bindir: bin
18
18
  cert_chain: []
19
19
 
20
- date: 2011-12-01 00:00:00 -05:00
20
+ date: 2011-12-09 00:00:00 -05:00
21
21
  default_executable:
22
22
  dependencies:
23
23
  - !ruby/object:Gem::Dependency
24
- name: rake
25
- prerelease: false
26
- requirement: &id001 !ruby/object:Gem::Requirement
27
- none: false
24
+ version_requirements: &id001 !ruby/object:Gem::Requirement
28
25
  requirements:
29
26
  - - ">="
30
27
  - !ruby/object:Gem::Version
31
- hash: 3
32
28
  segments:
33
29
  - 0
30
+ segments_generated: true
34
31
  version: "0"
32
+ requirement: *id001
33
+ name: rake
34
+ prerelease: false
35
35
  type: :development
36
- version_requirements: *id001
37
36
  - !ruby/object:Gem::Dependency
38
- name: rspec
39
- prerelease: false
40
- requirement: &id002 !ruby/object:Gem::Requirement
41
- none: false
37
+ version_requirements: &id002 !ruby/object:Gem::Requirement
42
38
  requirements:
43
39
  - - ~>
44
40
  - !ruby/object:Gem::Version
45
- hash: 3
46
41
  segments:
47
42
  - 2
48
43
  - 0
44
+ segments_generated: true
49
45
  version: "2.0"
46
+ requirement: *id002
47
+ name: rspec
48
+ prerelease: false
50
49
  type: :development
51
- version_requirements: *id002
52
50
  - !ruby/object:Gem::Dependency
53
- name: guard
54
- prerelease: false
55
- requirement: &id003 !ruby/object:Gem::Requirement
56
- none: false
51
+ version_requirements: &id003 !ruby/object:Gem::Requirement
57
52
  requirements:
58
53
  - - ">="
59
54
  - !ruby/object:Gem::Version
60
- hash: 3
61
55
  segments:
62
56
  - 0
57
+ segments_generated: true
63
58
  version: "0"
59
+ requirement: *id003
60
+ name: guard
61
+ prerelease: false
64
62
  type: :development
65
- version_requirements: *id003
66
63
  - !ruby/object:Gem::Dependency
67
- name: guard-rspec
68
- prerelease: false
69
- requirement: &id004 !ruby/object:Gem::Requirement
70
- none: false
64
+ version_requirements: &id004 !ruby/object:Gem::Requirement
71
65
  requirements:
72
66
  - - ">="
73
67
  - !ruby/object:Gem::Version
74
- hash: 3
75
68
  segments:
76
69
  - 0
70
+ segments_generated: true
77
71
  version: "0"
72
+ requirement: *id004
73
+ name: guard-rspec
74
+ prerelease: false
78
75
  type: :development
79
- version_requirements: *id004
80
76
  - !ruby/object:Gem::Dependency
81
- name: growl_notify
82
- prerelease: false
83
- requirement: &id005 !ruby/object:Gem::Requirement
84
- none: false
77
+ version_requirements: &id005 !ruby/object:Gem::Requirement
85
78
  requirements:
86
79
  - - ">="
87
80
  - !ruby/object:Gem::Version
88
- hash: 3
89
81
  segments:
90
82
  - 0
83
+ segments_generated: true
91
84
  version: "0"
85
+ requirement: *id005
86
+ name: growl_notify
87
+ prerelease: false
92
88
  type: :development
93
- version_requirements: *id005
94
89
  - !ruby/object:Gem::Dependency
90
+ version_requirements: &id006 !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ segments:
95
+ - 0
96
+ segments_generated: true
97
+ version: "0"
98
+ requirement: *id006
95
99
  name: rb-fsevent
96
100
  prerelease: false
97
- requirement: &id006 !ruby/object:Gem::Requirement
98
- none: false
101
+ type: :development
102
+ - !ruby/object:Gem::Dependency
103
+ version_requirements: &id007 !ruby/object:Gem::Requirement
99
104
  requirements:
100
105
  - - ">="
101
106
  - !ruby/object:Gem::Version
102
- hash: 3
103
107
  segments:
104
108
  - 0
109
+ segments_generated: true
105
110
  version: "0"
111
+ requirement: *id007
112
+ name: fuubar
113
+ prerelease: false
106
114
  type: :development
107
- version_requirements: *id006
108
115
  description: Keep track of anything.
109
116
  email:
110
117
  - support@instrumentalapp.com
@@ -116,6 +123,7 @@ extra_rdoc_files: []
116
123
 
117
124
  files:
118
125
  - .gitignore
126
+ - .rspec
119
127
  - Gemfile
120
128
  - Guardfile
121
129
  - README.rdoc
@@ -142,27 +150,25 @@ rdoc_options: []
142
150
  require_paths:
143
151
  - lib
144
152
  required_ruby_version: !ruby/object:Gem::Requirement
145
- none: false
146
153
  requirements:
147
154
  - - ">="
148
155
  - !ruby/object:Gem::Version
149
- hash: 3
150
156
  segments:
151
157
  - 0
158
+ segments_generated: true
152
159
  version: "0"
153
160
  required_rubygems_version: !ruby/object:Gem::Requirement
154
- none: false
155
161
  requirements:
156
162
  - - ">="
157
163
  - !ruby/object:Gem::Version
158
- hash: 3
159
164
  segments:
160
165
  - 0
166
+ segments_generated: true
161
167
  version: "0"
162
168
  requirements: []
163
169
 
164
170
  rubyforge_project:
165
- rubygems_version: 1.6.1
171
+ rubygems_version: 1.3.6
166
172
  signing_key:
167
173
  specification_version: 3
168
174
  summary: Agent for reporting data to instrumentalapp.com