instrumental_agent 0.4.0 → 0.5.0
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/.rspec +1 -0
- data/Guardfile +1 -1
- data/bin/instrument_server +5 -223
- data/instrumental_agent.gemspec +1 -0
- data/lib/instrumental/agent.rb +23 -12
- data/lib/instrumental/version.rb +1 -1
- data/spec/agent_spec.rb +35 -0
- metadata +50 -44
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour --format Fuubar
|
data/Guardfile
CHANGED
data/bin/instrument_server
CHANGED
@@ -1,225 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
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
|
data/instrumental_agent.gemspec
CHANGED
data/lib/instrumental/agent.rb
CHANGED
@@ -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
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
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)
|
data/lib/instrumental/version.rb
CHANGED
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
|
-
|
5
|
-
prerelease:
|
4
|
+
prerelease: false
|
6
5
|
segments:
|
7
6
|
- 0
|
8
|
-
-
|
7
|
+
- 5
|
9
8
|
- 0
|
10
|
-
|
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-
|
20
|
+
date: 2011-12-09 00:00:00 -05:00
|
21
21
|
default_executable:
|
22
22
|
dependencies:
|
23
23
|
- !ruby/object:Gem::Dependency
|
24
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
98
|
-
|
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
|
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
|