instrumental_agent 0.8.3 → 0.9.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/CHANGELOG.md +4 -0
- data/Gemfile +5 -0
- data/README.md +1 -2
- data/ext/mkrf_conf.rb +20 -0
- data/instrumental_agent.gemspec +7 -4
- data/lib/instrumental/agent.rb +85 -26
- data/lib/instrumental/version.rb +1 -1
- data/spec/agent_spec.rb +51 -4
- data/spec/spec_helper.rb +4 -2
- data/spec/test_server.rb +1 -0
- metadata +26 -24
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -111,5 +111,4 @@ after "instrumental:util:deploy_end", "instrumental:record_deploy_notice"
|
|
111
111
|
|
112
112
|
## Troubleshooting & Help
|
113
113
|
|
114
|
-
We are here to help,
|
115
|
-
[support@instrumentalapp.com](mailto:support@instrumentalapp.com).
|
114
|
+
We are here to help. Email us at [support@instrumentalapp.com](mailto:support@instrumentalapp.com), or visit the [Instrumental Support](https://fastestforward.campfirenow.com/6b934) Campfire room.
|
data/ext/mkrf_conf.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rubygems/command.rb'
|
3
|
+
require 'rubygems/dependency_installer.rb'
|
4
|
+
begin
|
5
|
+
Gem::Command.build_args = ARGV
|
6
|
+
rescue NoMethodError
|
7
|
+
end
|
8
|
+
inst = Gem::DependencyInstaller.new
|
9
|
+
begin
|
10
|
+
if RUBY_VERSION < "1.9"
|
11
|
+
inst.install "system_timer", "~> 1.2"
|
12
|
+
end
|
13
|
+
rescue
|
14
|
+
puts "Couldn't install system_timer gem, required on Ruby < 1.9"
|
15
|
+
exit(1)
|
16
|
+
end
|
17
|
+
|
18
|
+
f = File.open(File.join(File.dirname(__FILE__), "Rakefile"), "w") # create dummy rakefile to indicate success
|
19
|
+
f.write("task :default\n")
|
20
|
+
f.close
|
data/instrumental_agent.gemspec
CHANGED
@@ -14,11 +14,14 @@ Gem::Specification.new do |s|
|
|
14
14
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
15
15
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
16
16
|
s.require_paths = ["lib"]
|
17
|
+
s.extensions = 'ext/mkrf_conf.rb'
|
17
18
|
s.add_development_dependency(%q<rake>, [">= 0"])
|
18
19
|
s.add_development_dependency(%q<rspec>, ["~> 2.0"])
|
19
|
-
s.add_development_dependency(%q<guard>, [">= 0"])
|
20
|
-
s.add_development_dependency(%q<guard-rspec>, [">= 0"])
|
21
|
-
s.add_development_dependency(%q<growl_notify>, [">= 0"])
|
22
|
-
s.add_development_dependency(%q<rb-fsevent>, [">= 0"])
|
23
20
|
s.add_development_dependency(%q<fuubar>, [">= 0"])
|
21
|
+
if RUBY_VERSION >= "1.8.7"
|
22
|
+
s.add_development_dependency(%q<guard>, [">= 0"])
|
23
|
+
s.add_development_dependency(%q<guard-rspec>, [">= 0"])
|
24
|
+
s.add_development_dependency(%q<growl>, [">= 0"])
|
25
|
+
s.add_development_dependency(%q<rb-fsevent>, [">= 0"])
|
26
|
+
end
|
24
27
|
end
|
data/lib/instrumental/agent.rb
CHANGED
@@ -3,7 +3,12 @@ require 'instrumental/version'
|
|
3
3
|
require 'logger'
|
4
4
|
require 'thread'
|
5
5
|
require 'socket'
|
6
|
-
|
6
|
+
if RUBY_VERSION < "1.9"
|
7
|
+
require 'system_timer'
|
8
|
+
else
|
9
|
+
require 'timeout'
|
10
|
+
end
|
11
|
+
|
7
12
|
|
8
13
|
# Sets up a connection to the collector.
|
9
14
|
#
|
@@ -14,6 +19,8 @@ module Instrumental
|
|
14
19
|
MAX_RECONNECT_DELAY = 15
|
15
20
|
MAX_BUFFER = 5000
|
16
21
|
REPLY_TIMEOUT = 10
|
22
|
+
CONNECT_TIMEOUT = 20
|
23
|
+
EXIT_FLUSH_TIMEOUT = 5
|
17
24
|
|
18
25
|
attr_accessor :host, :port, :synchronous, :queue
|
19
26
|
attr_reader :connection, :enabled
|
@@ -60,12 +67,14 @@ module Instrumental
|
|
60
67
|
@enabled = options[:enabled]
|
61
68
|
@test_mode = options[:test_mode]
|
62
69
|
@synchronous = options[:synchronous]
|
70
|
+
@allow_reconnect = true
|
63
71
|
@pid = Process.pid
|
64
72
|
|
65
73
|
|
66
74
|
if @enabled
|
67
75
|
@failures = 0
|
68
76
|
@queue = Queue.new
|
77
|
+
@sync_mutex = Mutex.new
|
69
78
|
start_connection_worker
|
70
79
|
setup_cleanup_at_exit
|
71
80
|
end
|
@@ -136,7 +145,7 @@ module Instrumental
|
|
136
145
|
|
137
146
|
# Send a notice to the server (deploys, downtime, etc.)
|
138
147
|
#
|
139
|
-
#
|
148
|
+
# agent.notice('A notice')
|
140
149
|
def notice(note, time = Time.now, duration = 0)
|
141
150
|
if valid_note?(note)
|
142
151
|
send_command("notice", time.to_i, duration.to_i, note)
|
@@ -149,6 +158,19 @@ module Instrumental
|
|
149
158
|
nil
|
150
159
|
end
|
151
160
|
|
161
|
+
# Synchronously flush all pending metrics out to the server
|
162
|
+
# By default will not try to reconnect to the server if a
|
163
|
+
# connection failure happens during the flush, though you
|
164
|
+
# may optionally override this behavior by passing true.
|
165
|
+
#
|
166
|
+
# agent.flush
|
167
|
+
def flush(allow_reconnect = false)
|
168
|
+
queue_message('flush', {
|
169
|
+
:synchronous => true,
|
170
|
+
:allow_reconnect => allow_reconnect
|
171
|
+
})
|
172
|
+
end
|
173
|
+
|
152
174
|
def enabled?
|
153
175
|
@enabled
|
154
176
|
end
|
@@ -167,6 +189,11 @@ module Instrumental
|
|
167
189
|
|
168
190
|
private
|
169
191
|
|
192
|
+
def with_timeout(time, &block)
|
193
|
+
tmr_klass = RUBY_VERSION < "1.9" ? SystemTimer : Timeout
|
194
|
+
tmr_klass.timeout(time) { yield }
|
195
|
+
end
|
196
|
+
|
170
197
|
def valid_note?(note)
|
171
198
|
note !~ /[\n\r]/
|
172
199
|
end
|
@@ -207,13 +234,10 @@ module Instrumental
|
|
207
234
|
start_connection_worker
|
208
235
|
end
|
209
236
|
|
210
|
-
cmd = "%s %s\n" % [cmd, args.collect { |
|
237
|
+
cmd = "%s %s\n" % [cmd, args.collect { |a| a.to_s }.join(" ")]
|
211
238
|
if @queue.size < MAX_BUFFER
|
212
239
|
logger.debug "Queueing: #{cmd.chomp}"
|
213
|
-
|
214
|
-
@queue << cmd
|
215
|
-
Thread.stop if @synchronous
|
216
|
-
cmd
|
240
|
+
queue_message(cmd, { :synchronous => @synchronous })
|
217
241
|
else
|
218
242
|
logger.warn "Dropping command, queue full(#{@queue.size}): #{cmd.chomp}"
|
219
243
|
nil
|
@@ -221,12 +245,32 @@ module Instrumental
|
|
221
245
|
end
|
222
246
|
end
|
223
247
|
|
248
|
+
def queue_message(message, options = {})
|
249
|
+
if @enabled
|
250
|
+
options ||= {}
|
251
|
+
if options[:allow_reconnect].nil?
|
252
|
+
options[:allow_reconnect] = @allow_reconnect
|
253
|
+
end
|
254
|
+
synchronous = options.delete(:synchronous)
|
255
|
+
if synchronous
|
256
|
+
options[:sync_resource] ||= ConditionVariable.new
|
257
|
+
@queue << [message, options]
|
258
|
+
@sync_mutex.synchronize {
|
259
|
+
options[:sync_resource].wait(@sync_mutex)
|
260
|
+
}
|
261
|
+
else
|
262
|
+
@queue << [message, options]
|
263
|
+
end
|
264
|
+
end
|
265
|
+
message
|
266
|
+
end
|
267
|
+
|
224
268
|
def test_connection
|
225
269
|
# FIXME: Test connection state hack
|
226
270
|
begin
|
227
271
|
@socket.read_nonblock(1) # TODO: put data back?
|
228
272
|
rescue Errno::EAGAIN
|
229
|
-
#
|
273
|
+
# noop
|
230
274
|
end
|
231
275
|
end
|
232
276
|
|
@@ -235,16 +279,14 @@ module Instrumental
|
|
235
279
|
disconnect
|
236
280
|
logger.info "Starting thread"
|
237
281
|
@thread = Thread.new do
|
238
|
-
|
239
|
-
break if connection_worker
|
240
|
-
end
|
282
|
+
run_worker_loop
|
241
283
|
end
|
242
284
|
end
|
243
285
|
end
|
244
286
|
|
245
287
|
def send_with_reply_timeout(message)
|
246
288
|
@socket.puts message
|
247
|
-
|
289
|
+
with_timeout(REPLY_TIMEOUT) do
|
248
290
|
response = @socket.gets
|
249
291
|
if response.to_s.chomp != "ok"
|
250
292
|
raise "Bad Response #{response.inspect} to #{message.inspect}"
|
@@ -252,31 +294,44 @@ module Instrumental
|
|
252
294
|
end
|
253
295
|
end
|
254
296
|
|
255
|
-
def
|
297
|
+
def run_worker_loop
|
256
298
|
command_and_args = nil
|
299
|
+
command_options = nil
|
257
300
|
logger.info "connecting to collector"
|
258
|
-
@socket = TCPSocket.new(host, port)
|
301
|
+
@socket = with_timeout(CONNECT_TIMEOUT) { TCPSocket.new(host, port) }
|
259
302
|
logger.info "connected to collector at #{host}:#{port}"
|
260
303
|
send_with_reply_timeout "hello version #{Instrumental::VERSION} test_mode #{@test_mode}"
|
261
304
|
send_with_reply_timeout "authenticate #{@api_key}"
|
262
305
|
@failures = 0
|
263
306
|
loop do
|
264
|
-
command_and_args = @queue.pop
|
307
|
+
command_and_args, command_options = @queue.pop
|
308
|
+
sync_resource = command_options && command_options[:sync_resource]
|
265
309
|
test_connection
|
266
|
-
|
267
310
|
case command_and_args
|
268
311
|
when 'exit'
|
269
312
|
logger.info "exiting, #{@queue.size} commands remain"
|
270
313
|
return true
|
314
|
+
when 'flush'
|
315
|
+
release_resource = true
|
271
316
|
else
|
272
317
|
logger.debug "Sending: #{command_and_args.chomp}"
|
273
318
|
@socket.puts command_and_args
|
274
|
-
command_and_args = nil
|
275
319
|
end
|
276
|
-
|
320
|
+
command_and_args = nil
|
321
|
+
command_options = nil
|
322
|
+
if sync_resource
|
323
|
+
@sync_mutex.synchronize do
|
324
|
+
sync_resource.signal
|
325
|
+
end
|
326
|
+
end
|
277
327
|
end
|
278
328
|
rescue Exception => err
|
279
|
-
logger.
|
329
|
+
logger.debug err.backtrace.join("\n")
|
330
|
+
if @allow_reconnect == false ||
|
331
|
+
(command_options && command_options[:allow_reconnect] == false)
|
332
|
+
logger.error "Not trying to reconnect"
|
333
|
+
return
|
334
|
+
end
|
280
335
|
if command_and_args
|
281
336
|
logger.debug "requeueing: #{command_and_args}"
|
282
337
|
@queue << command_and_args
|
@@ -293,16 +348,20 @@ module Instrumental
|
|
293
348
|
|
294
349
|
def setup_cleanup_at_exit
|
295
350
|
at_exit do
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
351
|
+
logger.info "Cleaning up agent, queue empty: #{@queue.empty?}, thread running: #{@thread.alive?}"
|
352
|
+
@allow_reconnect = false
|
353
|
+
logger.info "exit received, currently #{@queue.size} commands to be sent"
|
354
|
+
queue_message('exit')
|
355
|
+
begin
|
356
|
+
with_timeout(EXIT_FLUSH_TIMEOUT) { @thread.join }
|
357
|
+
rescue Timeout::Error
|
358
|
+
if @queue.size > 0
|
359
|
+
logger.error "Timed out working agent thread on exit, dropping #{@queue.size} metrics"
|
300
360
|
else
|
301
|
-
logger.
|
302
|
-
@queue << 'exit'
|
303
|
-
@thread.join
|
361
|
+
logger.error "Timed out Instrumental Agent, exiting"
|
304
362
|
end
|
305
363
|
end
|
364
|
+
|
306
365
|
end
|
307
366
|
end
|
308
367
|
|
data/lib/instrumental/version.rb
CHANGED
data/spec/agent_spec.rb
CHANGED
@@ -27,6 +27,19 @@ describe Instrumental::Agent, "disabled" do
|
|
27
27
|
@server.connect_count.should == 0
|
28
28
|
end
|
29
29
|
|
30
|
+
it "should no op on flush without reconnect" do
|
31
|
+
1.upto(100) { @agent.gauge('disabled_test', 1) }
|
32
|
+
@agent.flush(false)
|
33
|
+
wait
|
34
|
+
@server.commands.should be_empty
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should no op on flush with reconnect" do
|
38
|
+
1.upto(100) { @agent.gauge('disabled_test', 1) }
|
39
|
+
@agent.flush(true)
|
40
|
+
wait
|
41
|
+
@server.commands.should be_empty
|
42
|
+
end
|
30
43
|
end
|
31
44
|
|
32
45
|
describe Instrumental::Agent, "enabled in test_mode" do
|
@@ -81,7 +94,7 @@ describe Instrumental::Agent, "enabled in test_mode" do
|
|
81
94
|
throw :an_exception
|
82
95
|
sleep 1
|
83
96
|
end
|
84
|
-
|
97
|
+
}.should raise_error
|
85
98
|
wait
|
86
99
|
@server.commands.last.should =~ /gauge time_value_test .* #{now.to_i}/
|
87
100
|
time = @server.commands.last.scan(/gauge time_value_test (.*) #{now.to_i}/)[0][0].to_f
|
@@ -216,6 +229,7 @@ describe Instrumental::Agent, "enabled" do
|
|
216
229
|
5.times do |i|
|
217
230
|
@agent.increment('overflow_test', i + 1, 300)
|
218
231
|
end
|
232
|
+
@agent.instance_variable_get(:@queue).size.should == 0
|
219
233
|
wait # let the server receive the commands
|
220
234
|
@server.commands.should include("increment overflow_test 1 300")
|
221
235
|
@server.commands.should include("increment overflow_test 2 300")
|
@@ -309,6 +323,15 @@ describe Instrumental::Agent, "enabled" do
|
|
309
323
|
wait
|
310
324
|
@server.commands.join("\n").should_not include("notice Test note")
|
311
325
|
end
|
326
|
+
|
327
|
+
it "should allow flushing pending values to the server" do
|
328
|
+
1.upto(100) { @agent.gauge('a', rand(50)) }
|
329
|
+
@agent.instance_variable_get(:@queue).size.should >= 100
|
330
|
+
@agent.flush
|
331
|
+
@agent.instance_variable_get(:@queue).size.should == 0
|
332
|
+
wait
|
333
|
+
@server.commands.grep(/^gauge a /).size.should == 100
|
334
|
+
end
|
312
335
|
end
|
313
336
|
|
314
337
|
describe Instrumental::Agent, "connection problems" do
|
@@ -333,7 +356,7 @@ describe Instrumental::Agent, "connection problems" do
|
|
333
356
|
wait
|
334
357
|
@agent.increment('reconnect_test', 1, 1234)
|
335
358
|
wait
|
336
|
-
@agent.queue.pop(true).should
|
359
|
+
@agent.queue.pop(true).should include("increment reconnect_test 1 1234\n")
|
337
360
|
end
|
338
361
|
|
339
362
|
it "should buffer commands when server is not responsive" do
|
@@ -342,7 +365,7 @@ describe Instrumental::Agent, "connection problems" do
|
|
342
365
|
wait
|
343
366
|
@agent.increment('reconnect_test', 1, 1234)
|
344
367
|
wait
|
345
|
-
@agent.queue.pop(true).should
|
368
|
+
@agent.queue.pop(true).should include("increment reconnect_test 1 1234\n")
|
346
369
|
end
|
347
370
|
|
348
371
|
it "should buffer commands when authentication fails" do
|
@@ -351,7 +374,31 @@ describe Instrumental::Agent, "connection problems" do
|
|
351
374
|
wait
|
352
375
|
@agent.increment('reconnect_test', 1, 1234)
|
353
376
|
wait
|
354
|
-
@agent.queue.pop(true).should
|
377
|
+
@agent.queue.pop(true).should include("increment reconnect_test 1 1234\n")
|
378
|
+
end
|
379
|
+
|
380
|
+
it "should send commands in a short-lived process" do
|
381
|
+
@server = TestServer.new
|
382
|
+
@agent = Instrumental::Agent.new('test_token', :collector => @server.host_and_port, :synchronous => false)
|
383
|
+
if pid = fork { @agent.increment('foo', 1, 1234) }
|
384
|
+
Process.wait(pid)
|
385
|
+
@server.commands.last.should == "increment foo 1 1234"
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
389
|
+
it "should not wait longer than EXIT_FLUSH_TIMEOUT seconds to exit a process" do
|
390
|
+
@server = TestServer.new
|
391
|
+
@agent = Instrumental::Agent.new('test_token', :collector => @server.host_and_port, :synchronous => false)
|
392
|
+
TCPSocket.stub!(:new) { |*args| sleep(5) && StringIO.new }
|
393
|
+
with_constants('Instrumental::Agent::EXIT_FLUSH_TIMEOUT' => 3) do
|
394
|
+
if (pid = fork { @agent.increment('foo', 1) })
|
395
|
+
tm = Time.now.to_f
|
396
|
+
Process.wait(pid)
|
397
|
+
diff = Time.now.to_f - tm
|
398
|
+
diff.should >= 3
|
399
|
+
diff.should < 5
|
400
|
+
end
|
401
|
+
end
|
355
402
|
end
|
356
403
|
end
|
357
404
|
|
data/spec/spec_helper.rb
CHANGED
@@ -15,8 +15,10 @@ end
|
|
15
15
|
|
16
16
|
|
17
17
|
def parse_constant(constant)
|
18
|
-
|
19
|
-
|
18
|
+
constant = constant.to_s
|
19
|
+
parts = constant.split("::")
|
20
|
+
constant_name = parts.pop
|
21
|
+
source = parts.join("::")
|
20
22
|
[source.constantize, constant_name]
|
21
23
|
end
|
22
24
|
|
data/spec/test_server.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: instrumental_agent
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -12,11 +12,11 @@ authors:
|
|
12
12
|
autorequire:
|
13
13
|
bindir: bin
|
14
14
|
cert_chain: []
|
15
|
-
date: 2012-02-
|
15
|
+
date: 2012-02-20 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: rake
|
19
|
-
requirement: &
|
19
|
+
requirement: &70233623514200 !ruby/object:Gem::Requirement
|
20
20
|
none: false
|
21
21
|
requirements:
|
22
22
|
- - ! '>='
|
@@ -24,10 +24,10 @@ dependencies:
|
|
24
24
|
version: '0'
|
25
25
|
type: :development
|
26
26
|
prerelease: false
|
27
|
-
version_requirements: *
|
27
|
+
version_requirements: *70233623514200
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: rspec
|
30
|
-
requirement: &
|
30
|
+
requirement: &70233623513680 !ruby/object:Gem::Requirement
|
31
31
|
none: false
|
32
32
|
requirements:
|
33
33
|
- - ~>
|
@@ -35,10 +35,10 @@ dependencies:
|
|
35
35
|
version: '2.0'
|
36
36
|
type: :development
|
37
37
|
prerelease: false
|
38
|
-
version_requirements: *
|
38
|
+
version_requirements: *70233623513680
|
39
39
|
- !ruby/object:Gem::Dependency
|
40
|
-
name:
|
41
|
-
requirement: &
|
40
|
+
name: fuubar
|
41
|
+
requirement: &70233623513200 !ruby/object:Gem::Requirement
|
42
42
|
none: false
|
43
43
|
requirements:
|
44
44
|
- - ! '>='
|
@@ -46,10 +46,10 @@ dependencies:
|
|
46
46
|
version: '0'
|
47
47
|
type: :development
|
48
48
|
prerelease: false
|
49
|
-
version_requirements: *
|
49
|
+
version_requirements: *70233623513200
|
50
50
|
- !ruby/object:Gem::Dependency
|
51
|
-
name: guard
|
52
|
-
requirement: &
|
51
|
+
name: guard
|
52
|
+
requirement: &70233623512700 !ruby/object:Gem::Requirement
|
53
53
|
none: false
|
54
54
|
requirements:
|
55
55
|
- - ! '>='
|
@@ -57,10 +57,10 @@ dependencies:
|
|
57
57
|
version: '0'
|
58
58
|
type: :development
|
59
59
|
prerelease: false
|
60
|
-
version_requirements: *
|
60
|
+
version_requirements: *70233623512700
|
61
61
|
- !ruby/object:Gem::Dependency
|
62
|
-
name:
|
63
|
-
requirement: &
|
62
|
+
name: guard-rspec
|
63
|
+
requirement: &70233623512220 !ruby/object:Gem::Requirement
|
64
64
|
none: false
|
65
65
|
requirements:
|
66
66
|
- - ! '>='
|
@@ -68,10 +68,10 @@ dependencies:
|
|
68
68
|
version: '0'
|
69
69
|
type: :development
|
70
70
|
prerelease: false
|
71
|
-
version_requirements: *
|
71
|
+
version_requirements: *70233623512220
|
72
72
|
- !ruby/object:Gem::Dependency
|
73
|
-
name:
|
74
|
-
requirement: &
|
73
|
+
name: growl
|
74
|
+
requirement: &70233623511740 !ruby/object:Gem::Requirement
|
75
75
|
none: false
|
76
76
|
requirements:
|
77
77
|
- - ! '>='
|
@@ -79,10 +79,10 @@ dependencies:
|
|
79
79
|
version: '0'
|
80
80
|
type: :development
|
81
81
|
prerelease: false
|
82
|
-
version_requirements: *
|
82
|
+
version_requirements: *70233623511740
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
85
|
-
requirement: &
|
84
|
+
name: rb-fsevent
|
85
|
+
requirement: &70233623511260 !ruby/object:Gem::Requirement
|
86
86
|
none: false
|
87
87
|
requirements:
|
88
88
|
- - ! '>='
|
@@ -90,12 +90,13 @@ dependencies:
|
|
90
90
|
version: '0'
|
91
91
|
type: :development
|
92
92
|
prerelease: false
|
93
|
-
version_requirements: *
|
93
|
+
version_requirements: *70233623511260
|
94
94
|
description: Track anything.
|
95
95
|
email:
|
96
96
|
- support@instrumentalapp.com
|
97
97
|
executables: []
|
98
|
-
extensions:
|
98
|
+
extensions:
|
99
|
+
- ext/mkrf_conf.rb
|
99
100
|
extra_rdoc_files: []
|
100
101
|
files:
|
101
102
|
- .gitignore
|
@@ -105,6 +106,7 @@ files:
|
|
105
106
|
- Guardfile
|
106
107
|
- README.md
|
107
108
|
- Rakefile
|
109
|
+
- ext/mkrf_conf.rb
|
108
110
|
- instrumental_agent.gemspec
|
109
111
|
- lib/instrumental/agent.rb
|
110
112
|
- lib/instrumental/capistrano.rb
|
@@ -128,7 +130,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
128
130
|
version: '0'
|
129
131
|
segments:
|
130
132
|
- 0
|
131
|
-
hash: -
|
133
|
+
hash: -278624242877907037
|
132
134
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
133
135
|
none: false
|
134
136
|
requirements:
|
@@ -137,7 +139,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
137
139
|
version: '0'
|
138
140
|
segments:
|
139
141
|
- 0
|
140
|
-
hash: -
|
142
|
+
hash: -278624242877907037
|
141
143
|
requirements: []
|
142
144
|
rubyforge_project:
|
143
145
|
rubygems_version: 1.8.15
|