scout 5.4.5.1.alpha → 5.4.6.alpha
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/scout/plugin.rb +0 -9
- data/lib/scout/streamer.rb +85 -65
- data/lib/scout/version.rb +1 -1
- data/test/scout_test.rb +39 -7
- metadata +5 -5
data/lib/scout/plugin.rb
CHANGED
@@ -133,15 +133,6 @@ module Scout
|
|
133
133
|
END
|
134
134
|
end
|
135
135
|
|
136
|
-
# resets everything except memory. Memory stays intact. This is used for real-time reporting
|
137
|
-
def reset!
|
138
|
-
@data_for_server = { :reports => [ ],
|
139
|
-
:alerts => [ ],
|
140
|
-
:errors => [ ],
|
141
|
-
:summaries => [ ],
|
142
|
-
:memory => @memory }
|
143
|
-
end
|
144
|
-
|
145
136
|
#
|
146
137
|
# Usage:
|
147
138
|
#
|
data/lib/scout/streamer.rb
CHANGED
@@ -30,45 +30,43 @@ module Scout
|
|
30
30
|
load_history
|
31
31
|
|
32
32
|
# get the array of plugins, AKA the plugin plan
|
33
|
-
@
|
34
|
-
info("Starting streamer with key=#{streaming_key} and plugin_ids: #{plugin_ids.inspect}. #{@history_file} includes plugin ids #{@
|
33
|
+
@all_plugins = Array(@history["old_plugins"])
|
34
|
+
info("Starting streamer with key=#{streaming_key} and plugin_ids: #{plugin_ids.inspect}. #{@history_file} includes plugin ids #{@all_plugins.map{|p|p['id']}.inspect}")
|
35
35
|
|
36
|
-
#
|
37
|
-
|
38
|
-
plugin_data=@plugin_plan.find{|plugin| plugin['id'] && plugin['id'].to_i == plugin_id}
|
39
|
-
if plugin_data
|
40
|
-
begin
|
41
|
-
plugin=get_instance_of(plugin_data, plugin_id)
|
42
|
-
info("#{i+1}) plugin_id=#{plugin_id} - instance of #{plugin.class.name} created for #{plugin_data['name']}" )
|
43
|
-
if plugin.is_a?(Plugin) # safety check that it's an instance of Plugin
|
44
|
-
@plugin_hashes.push(:instance=>plugin, :id=>plugin_id, :name=>plugin_data['name'])
|
45
|
-
end
|
46
|
-
rescue Exception
|
47
|
-
error("Encountered an error compiling: #{$!.message}")
|
48
|
-
error $!.backtrace.join('\n')
|
49
|
-
end
|
50
|
-
else
|
51
|
-
info("#{i+1}) plugin_id=#{plugin_id} specified in #{plugin_ids.inspect} but not found in #{@history_file}")
|
52
|
-
end
|
53
|
-
end
|
36
|
+
# selected_plugins is subset of the @all_plugins -- those selected in plugin_ids
|
37
|
+
selected_plugins = compile_plugins(@all_plugins, plugin_ids)
|
54
38
|
|
55
|
-
info "Finished compilation. #{@plugin_plan.size} plugins; #{@plugin_hashes.size} instances instantiated"
|
56
39
|
|
57
40
|
# main loop. Continue running until global $continue_streaming is set to false OR we've been running for MAX DURATION
|
58
41
|
iteration=1 # use this to log the data at a couple points
|
59
42
|
while(streamer_start_time+MAX_DURATION > Time.now && $continue_streaming) do
|
60
43
|
plugins=[]
|
61
|
-
|
62
|
-
plugin
|
44
|
+
selected_plugins.each_with_index do |plugin_hash,i|
|
45
|
+
# create an actual instance of the plugin
|
46
|
+
plugin=get_instance_of(plugin_hash)
|
47
|
+
|
63
48
|
start_time=Time.now
|
64
|
-
|
65
|
-
|
49
|
+
|
50
|
+
data = {}
|
51
|
+
begin
|
52
|
+
Timeout.timeout(30, PluginTimeoutError) do
|
53
|
+
data = plugin.run
|
54
|
+
end
|
55
|
+
rescue Timeout::Error, PluginTimeoutError
|
56
|
+
error "Plugin took too long to run."
|
57
|
+
end
|
58
|
+
|
66
59
|
duration=((Time.now-start_time)*1000).to_i
|
67
60
|
|
61
|
+
id_and_name = plugin_hash['id_and_name']
|
62
|
+
@history["last_runs"][id_and_name] = start_time
|
63
|
+
@history["memory"][id_and_name] = data[:memory]
|
64
|
+
|
68
65
|
plugins << {:duration=>duration,
|
69
66
|
:fields=>plugin.reports.inject{|memo,hash|memo.merge(hash)},
|
70
|
-
:name=>plugin_hash[
|
71
|
-
:id=>plugin_hash[
|
67
|
+
:name=>plugin_hash['name'],
|
68
|
+
:id=>plugin_hash['id'],
|
69
|
+
:class=>plugin_hash['code_class']}
|
72
70
|
end
|
73
71
|
|
74
72
|
bundle={:hostname=>hostname,
|
@@ -76,6 +74,7 @@ module Scout
|
|
76
74
|
:num_processes=>`ps -e | wc -l`.chomp.to_i,
|
77
75
|
:plugins=>plugins }
|
78
76
|
|
77
|
+
# stream the data via pusherapp
|
79
78
|
begin
|
80
79
|
Pusher[streaming_key].trigger!('server_data', bundle)
|
81
80
|
rescue Pusher::Error => e
|
@@ -85,15 +84,7 @@ module Scout
|
|
85
84
|
|
86
85
|
if iteration == 2 || iteration == 100
|
87
86
|
info "Run #{iteration} data dump:"
|
88
|
-
info bundle.
|
89
|
-
end
|
90
|
-
|
91
|
-
if false
|
92
|
-
# debugging
|
93
|
-
File.open(File.join(File.dirname(@history_file),"debug.txt"),"w") do |f|
|
94
|
-
f.puts "... sleeping @ #{Time.now.strftime("%I:%M:%S %p")}..."
|
95
|
-
f.puts bundle.to_yaml
|
96
|
-
end
|
87
|
+
info bundle.inspect
|
97
88
|
end
|
98
89
|
|
99
90
|
sleep(SLEEP)
|
@@ -106,42 +97,71 @@ module Scout
|
|
106
97
|
|
107
98
|
private
|
108
99
|
|
109
|
-
#
|
110
|
-
|
111
|
-
|
100
|
+
# Compile instances of the plugins specified in the passed plugin_ids
|
101
|
+
def compile_plugins(all_plugins,plugin_ids)
|
102
|
+
num_classes_compiled=0
|
103
|
+
selected_plugins=[]
|
104
|
+
plugin_ids.each_with_index do |plugin_id,i|
|
105
|
+
plugin=all_plugins.find{|plugin| plugin['id'] && plugin['id'].to_i == plugin_id}
|
106
|
+
if plugin
|
107
|
+
begin
|
108
|
+
# take care of plugin overrides
|
109
|
+
local_path = File.join(File.dirname(@history_file), "#{plugin_id}.rb")
|
110
|
+
if File.exist?(local_path)
|
111
|
+
code_to_run = File.read(local_path)
|
112
|
+
else
|
113
|
+
code_to_run=plugin['code'] || ""
|
114
|
+
end
|
112
115
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
116
|
+
code_class=Plugin.extract_code_class(code_to_run)
|
117
|
+
|
118
|
+
# eval the plugin code if it's not already defined
|
119
|
+
if !Object.const_defined?(code_class)
|
120
|
+
eval(code_to_run, TOPLEVEL_BINDING, plugin['name'] )
|
121
|
+
|
122
|
+
# turn certain methods into null-ops, so summaries aren't generated. Note that this is ad-hoc, and not future-proof.
|
123
|
+
klass=Scout::Plugin.const_get(code_class)
|
124
|
+
if code_class=="RailsRequests"
|
125
|
+
klass.module_eval { def analyze;end; }
|
126
|
+
end
|
127
|
+
if code_class=="ApacheAnalyzer"
|
128
|
+
klass.module_eval { def generate_log_analysis;end; }
|
129
|
+
end
|
130
|
+
info "#{i+1}) #{plugin['name']} (id=#{plugin_id}) - #{code_class} compiled."
|
131
|
+
num_classes_compiled+=1
|
132
|
+
else
|
133
|
+
info "#{i+1}) #{plugin['name']} (id=#{plugin_id}) - #{code_class} was compiled previously."
|
134
|
+
end
|
135
|
+
# we'll use code_class and id_and name again
|
136
|
+
plugin['code_class']=code_class
|
137
|
+
plugin['id_and_name']= "#{plugin['id']}-#{plugin['name']}".sub(/\A-/, "")
|
138
|
+
selected_plugins << plugin
|
139
|
+
rescue Exception
|
140
|
+
error("Encountered an error compiling: #{$!.message}")
|
141
|
+
error $!.backtrace.join('\n')
|
142
|
+
end
|
143
|
+
else
|
144
|
+
info("#{i+1}) plugin_id=#{plugin_id} specified in #{plugin_ids.inspect} but not found in #{@history_file}")
|
145
|
+
end
|
119
146
|
end
|
120
147
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
memory = @history["memory"][id_and_name] ||
|
125
|
-
@history["memory"][plugin['name']]
|
126
|
-
options=(plugin['options'] || Hash.new)
|
127
|
-
options.merge!(:tuner_days=>"")
|
128
|
-
|
129
|
-
code_class=Plugin.extract_code_class(code_to_run)
|
130
|
-
|
131
|
-
# eval the plugin code if it's not already defined
|
132
|
-
if !Plugin.const_defined?(code_class)
|
133
|
-
eval(code_to_run, TOPLEVEL_BINDING, plugin['path'] || plugin['name'] )
|
134
|
-
end
|
148
|
+
info "Finished compilation. #{num_classes_compiled} plugin classes compiled for the #{plugin_ids.size} plugin(s) needed for streaming."
|
149
|
+
return selected_plugins
|
150
|
+
end
|
135
151
|
|
136
|
-
|
137
|
-
|
152
|
+
# plugin is a hash of plugin data from the history file (id, name, code, etc).
|
153
|
+
# This plugin returns an instantiated instance of the plugin
|
154
|
+
def get_instance_of(plugin)
|
138
155
|
|
139
|
-
|
140
|
-
|
141
|
-
|
156
|
+
id_and_name = plugin['id_and_name']
|
157
|
+
last_run = @history["last_runs"][id_and_name]
|
158
|
+
memory = @history["memory"][id_and_name]
|
159
|
+
options=(plugin['options'] || Hash.new)
|
160
|
+
options.merge!(:tuner_days=>"")
|
142
161
|
|
143
162
|
# finally, return an instance of the plugin
|
144
|
-
klass.
|
163
|
+
klass=Scout::Plugin.const_get(plugin['code_class'])
|
164
|
+
return klass.load(last_run, (memory || Hash.new), options)
|
145
165
|
end
|
146
166
|
|
147
167
|
|
data/lib/scout/version.rb
CHANGED
data/test/scout_test.rb
CHANGED
@@ -410,7 +410,7 @@ mybar=100
|
|
410
410
|
scout(@client.key) # to write the initial history file. Sinatra MUST be running
|
411
411
|
$continue_streaming = true # so the streamer will run once
|
412
412
|
streamer=Scout::Streamer.new("http://none", "bogus_client_key", PATH_TO_DATA_FILE, [@client.plugins.first.id]+plugins.map(&:id), "bogus_streaming_key",nil) # for debugging, make last arg Logger.new(STDOUT)
|
413
|
-
res =
|
413
|
+
res = Pusher::Channel.streamer_data # via the mock_streamer call
|
414
414
|
|
415
415
|
assert res.is_a?(Hash)
|
416
416
|
assert res[:plugins].is_a?(Array)
|
@@ -422,6 +422,7 @@ mybar=100
|
|
422
422
|
end # end of mock_pusher
|
423
423
|
end
|
424
424
|
|
425
|
+
# the local plugin shouldn't report
|
425
426
|
def test_streamer_with_local_plugin
|
426
427
|
local_path=File.join(AGENT_DIR,"my_local_plugin.rb")
|
427
428
|
code=<<-EOC
|
@@ -435,11 +436,11 @@ mybar=100
|
|
435
436
|
mock_pusher do
|
436
437
|
$continue_streaming = true # so the streamer will run once
|
437
438
|
streamer=Scout::Streamer.new("http://none", "bogus_client_key", PATH_TO_DATA_FILE, [@client.plugins.first.id], "bogus_streaming_key",nil) # for debugging, make last arg Logger.new(STDOUT)
|
438
|
-
res =
|
439
|
+
res = Pusher::Channel.streamer_data # Pusher::Channel.streamer_data via the mock_streamer call
|
439
440
|
|
440
441
|
assert res.is_a?(Hash)
|
441
442
|
assert res[:plugins].is_a?(Array)
|
442
|
-
assert_equal 1, res[:plugins].size
|
443
|
+
assert_equal 1, res[:plugins].size # this is NOT the local plugin, it's a regular plugin that's already there
|
443
444
|
assert_equal 2, res[:plugins][0][:fields][:load]
|
444
445
|
end # end of mock_pusher
|
445
446
|
end
|
@@ -469,6 +470,20 @@ mybar=100
|
|
469
470
|
assert_nil @client.reload.streamer_command
|
470
471
|
end
|
471
472
|
|
473
|
+
def test_streamer_with_memory
|
474
|
+
mock_pusher(3) do
|
475
|
+
plugin = create_plugin(@client, "memory plugin", PLUGIN_FIXTURES[:memory][:code], PLUGIN_FIXTURES[:memory][:sig])
|
476
|
+
scout(@client.key)
|
477
|
+
#puts YAML.load(File.read(PATH_TO_DATA_FILE))['memory'].to_yaml
|
478
|
+
|
479
|
+
$continue_streaming = true # so the streamer will start running
|
480
|
+
# for debugging, make last arg Logger.new(STDOUT)
|
481
|
+
streamer=Scout::Streamer.new("http://none", "bogus_client_key", PATH_TO_DATA_FILE, [plugin.id], "bogus_streaming_key",nil)
|
482
|
+
res = Pusher::Channel.streamer_data # Pusher::Channel.streamer_data via the mock_pusher call
|
483
|
+
assert_equal 3, res[:plugins][0][:fields][:v], "after the two streamer runs, this plugin should report v=3 -- it increments each run"
|
484
|
+
end
|
485
|
+
end
|
486
|
+
|
472
487
|
|
473
488
|
######################
|
474
489
|
### Helper Methods ###
|
@@ -585,16 +600,23 @@ mybar=100
|
|
585
600
|
p
|
586
601
|
end
|
587
602
|
|
588
|
-
# this with a block to mock the pusher call. You can access the streamer data through the
|
603
|
+
# this with a block to mock the pusher call. You can access the streamer data through the Pusher::Channel.streamer_data
|
589
604
|
# Must be called with a code block
|
590
|
-
def mock_pusher
|
605
|
+
def mock_pusher(num_runs=1)
|
591
606
|
# redefine the trigger! method, so the streamer doesn't loop indefinitely. We can't just mock it, because
|
592
607
|
# we need to set the $continue_streaming=false
|
608
|
+
$num_runs_for_mock_pusher=num_runs
|
593
609
|
Pusher::Channel.module_eval do
|
594
610
|
alias orig_trigger! trigger!
|
611
|
+
def self.streamer_data;@@streamer_data;end # for getting the data back out
|
595
612
|
def trigger!(event_name, data, socket=nil)
|
596
|
-
|
597
|
-
$
|
613
|
+
@num_run_for_tests = @num_run_for_tests ? @num_run_for_tests+1 : 1
|
614
|
+
# puts "in mock pusher trigger! This is run #{@num_run_for_tests} of #{$num_runs_for_mock_pusher}"
|
615
|
+
@@streamer_data = data
|
616
|
+
if @num_run_for_tests >= $num_runs_for_mock_pusher
|
617
|
+
$continue_streaming=false
|
618
|
+
@num_run_for_tests=nil
|
619
|
+
end
|
598
620
|
end
|
599
621
|
end
|
600
622
|
yield # must be called with a block
|
@@ -624,6 +646,16 @@ v6GYcfGCAsiZvnjl/2wsqjvrAl/zyuSW/s5YLsjxca1LEvhkyxbpnDGuj32k
|
|
624
646
|
7gtxXcblNP6hm7A6AlBzP0hwYORR//gpLLGtmT5ewltHUj9aSUY0GQle3lvH
|
625
647
|
/uzBDoV1x6mEYR2jPO5QQxL3BvTBvpC06ec8M/ZWbO9IwA7/DOs+vYfngxlp
|
626
648
|
jbtpAK9QCaAalKy/Z29os/7aViHy9z9IVCpC/z3MDA==
|
649
|
+
EOS
|
650
|
+
},
|
651
|
+
:memory=>{:code=>"class MemoryPlugin < Scout::Plugin;def build_report; v=memory(:v)||0; report(:v=>v);remember(:v,v+1);end;end",
|
652
|
+
:sig=><<EOS
|
653
|
+
5GNahpevN9VW5f7rmo6Cfq+2TWp8pwukxbE5laAZtDea44KaNE9gSMfiNCqz
|
654
|
+
rLAHvNXITJi0uI1rm+HXrak6L5oGvSouivCPtPTq1jRBy4QX2Sk9+gNEtTa8
|
655
|
+
HXu5TIQLJ/+IYHIG2E5FWcbfddR8cmJkIl4zGs93IatQNTENksRzphob7Cz8
|
656
|
+
wBwOHDG78kJ4TWEV5NIa5rLW8y2ltthfEPCTnS8/Zxa6h0qFtNrUWiU2KKtp
|
657
|
+
xTbJ3RgWKUnAR3YrEGB/JjjkPN2FrsDRvlClGujaYIWpWGkf+GZcpUn+QYxP
|
658
|
+
w7/kFz29Ds4hJRg2E2cWCHPtrD4dI0p/1iwP4XsxOw==
|
627
659
|
EOS
|
628
660
|
}
|
629
661
|
} # end of PLUGIN_FIXTURES
|
metadata
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: scout
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.4.
|
5
|
-
prerelease:
|
4
|
+
version: 5.4.6.alpha
|
5
|
+
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Andre Lewis
|
@@ -11,11 +11,11 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2011-12-
|
14
|
+
date: 2011-12-17 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: elif
|
18
|
-
requirement: &
|
18
|
+
requirement: &70103547353160 !ruby/object:Gem::Requirement
|
19
19
|
none: false
|
20
20
|
requirements:
|
21
21
|
- - ! '>='
|
@@ -23,7 +23,7 @@ dependencies:
|
|
23
23
|
version: '0'
|
24
24
|
type: :runtime
|
25
25
|
prerelease: false
|
26
|
-
version_requirements: *
|
26
|
+
version_requirements: *70103547353160
|
27
27
|
description: ! 'Scout makes monitoring and reporting on your web applications as flexible
|
28
28
|
and simple as possible.
|
29
29
|
|