scout 5.3.5 → 5.4.4.alpha
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 +6 -0
- data/CHANGELOG +0 -12
- data/Gemfile +4 -0
- data/README +8 -0
- data/Rakefile +6 -108
- data/bin/scout +1 -0
- data/lib/scout.rb +5 -4
- data/lib/scout/command.rb +11 -12
- data/lib/scout/command/install.rb +1 -1
- data/lib/scout/command/run.rb +13 -1
- data/lib/scout/command/sign.rb +2 -8
- data/lib/scout/command/stream.rb +50 -0
- data/lib/scout/command/test.rb +1 -1
- data/lib/scout/daemon_spawn.rb +215 -0
- data/lib/scout/plugin.rb +20 -1
- data/lib/scout/server.rb +16 -111
- data/lib/scout/server_base.rb +100 -0
- data/lib/scout/streamer.rb +162 -0
- data/lib/scout/streamer_control.rb +43 -0
- data/lib/scout/version.rb +3 -0
- data/scout.gemspec +27 -0
- data/test/plugins/disk_usage.rb +86 -0
- data/test/scout_test.rb +598 -0
- data/vendor/pusher-gem/Gemfile +2 -0
- data/vendor/pusher-gem/LICENSE +20 -0
- data/vendor/pusher-gem/README.md +80 -0
- data/vendor/pusher-gem/Rakefile +11 -0
- data/vendor/pusher-gem/examples/async_message.rb +28 -0
- data/vendor/pusher-gem/lib/pusher.rb +107 -0
- data/vendor/pusher-gem/lib/pusher/channel.rb +154 -0
- data/vendor/pusher-gem/lib/pusher/request.rb +107 -0
- data/vendor/pusher-gem/pusher.gemspec +28 -0
- data/vendor/pusher-gem/spec/channel_spec.rb +274 -0
- data/vendor/pusher-gem/spec/pusher_spec.rb +87 -0
- data/vendor/pusher-gem/spec/spec_helper.rb +13 -0
- data/vendor/ruby-hmac/History.txt +15 -0
- data/vendor/ruby-hmac/Manifest.txt +11 -0
- data/vendor/ruby-hmac/README.md +41 -0
- data/vendor/ruby-hmac/Rakefile +23 -0
- data/vendor/ruby-hmac/lib/hmac-md5.rb +11 -0
- data/vendor/ruby-hmac/lib/hmac-rmd160.rb +11 -0
- data/vendor/ruby-hmac/lib/hmac-sha1.rb +11 -0
- data/vendor/ruby-hmac/lib/hmac-sha2.rb +25 -0
- data/vendor/ruby-hmac/lib/hmac.rb +118 -0
- data/vendor/ruby-hmac/lib/ruby_hmac.rb +2 -0
- data/vendor/ruby-hmac/ruby-hmac.gemspec +33 -0
- data/vendor/ruby-hmac/test/test_hmac.rb +89 -0
- data/vendor/signature/.document +5 -0
- data/vendor/signature/.gitignore +21 -0
- data/vendor/signature/Gemfile +3 -0
- data/vendor/signature/Gemfile.lock +29 -0
- data/vendor/signature/LICENSE +20 -0
- data/vendor/signature/README.md +55 -0
- data/vendor/signature/Rakefile +2 -0
- data/vendor/signature/VERSION +1 -0
- data/vendor/signature/lib/signature.rb +142 -0
- data/vendor/signature/lib/signature/version.rb +3 -0
- data/vendor/signature/signature.gemspec +22 -0
- data/vendor/signature/spec/signature_spec.rb +176 -0
- data/vendor/signature/spec/spec_helper.rb +10 -0
- data/vendor/util/lib/core_extensions.rb +60 -0
- metadata +120 -84
- data/AUTHORS +0 -4
- data/COPYING +0 -340
- data/INSTALL +0 -18
- data/TODO +0 -6
data/lib/scout/plugin.rb
CHANGED
|
@@ -49,6 +49,16 @@ module Scout
|
|
|
49
49
|
code =~ EMBEDDED_OPTIONS_REGEX
|
|
50
50
|
return $2
|
|
51
51
|
end
|
|
52
|
+
|
|
53
|
+
def extract_code_class(code)
|
|
54
|
+
match = /class\s\b(\w*)\s+?<\s+Scout::Plugin/.match(code)
|
|
55
|
+
|
|
56
|
+
if match
|
|
57
|
+
return match[1]
|
|
58
|
+
else
|
|
59
|
+
raise ArgumentError, "can't identify plugin class"
|
|
60
|
+
end
|
|
61
|
+
end
|
|
52
62
|
end
|
|
53
63
|
|
|
54
64
|
# Creates a new Scout Plugin to run.
|
|
@@ -122,7 +132,16 @@ module Scout
|
|
|
122
132
|
alias_method :add_#{kind}, :#{kind}
|
|
123
133
|
END
|
|
124
134
|
end
|
|
125
|
-
|
|
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
|
+
|
|
126
145
|
#
|
|
127
146
|
# Usage:
|
|
128
147
|
#
|
data/lib/scout/server.rb
CHANGED
|
@@ -1,29 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
require "timeout"
|
|
7
|
-
require "stringio"
|
|
8
|
-
require "zlib"
|
|
9
|
-
require "socket"
|
|
10
|
-
require "base64"
|
|
11
|
-
|
|
12
|
-
$LOAD_PATH << File.join(File.dirname(__FILE__), *%w[.. .. vendor json_pure lib])
|
|
1
|
+
|
|
2
|
+
Dir.glob(File.join(File.dirname(__FILE__), *%w[.. .. vendor *])).each do |dir|
|
|
3
|
+
$LOAD_PATH << File.join(dir,"lib")
|
|
4
|
+
end
|
|
5
|
+
|
|
13
6
|
require "json"
|
|
7
|
+
require "pusher"
|
|
14
8
|
|
|
15
9
|
module Scout
|
|
16
|
-
class Server
|
|
17
|
-
# A new class for plugin Timeout errors.
|
|
18
|
-
class PluginTimeoutError < RuntimeError; end
|
|
19
|
-
# A new class for API Timeout errors.
|
|
20
|
-
class APITimeoutError < RuntimeError; end
|
|
21
|
-
|
|
22
|
-
# Headers passed up with all API requests.
|
|
23
|
-
HTTP_HEADERS = { "Client-Version" => Scout::VERSION,
|
|
24
|
-
"Client-Hostname" => Socket.gethostname,
|
|
25
|
-
"Accept-Encoding" => "gzip" }
|
|
26
|
-
|
|
10
|
+
class Server < Scout::ServerBase
|
|
27
11
|
#
|
|
28
12
|
# A plugin cannot take more than DEFAULT_PLUGIN_TIMEOUT seconds to execute,
|
|
29
13
|
# otherwise, a timeout error is generated. This can be overriden by
|
|
@@ -39,20 +23,20 @@ module Scout
|
|
|
39
23
|
attr_reader :new_plan
|
|
40
24
|
attr_reader :directives
|
|
41
25
|
attr_reader :plugin_config
|
|
26
|
+
attr_reader :streamer_command
|
|
42
27
|
|
|
43
28
|
# Creates a new Scout Server connection.
|
|
44
|
-
def initialize(server, client_key, history_file, logger = nil, server_name=nil
|
|
29
|
+
def initialize(server, client_key, history_file, logger = nil, server_name=nil)
|
|
45
30
|
@server = server
|
|
46
31
|
@client_key = client_key
|
|
47
32
|
@history_file = history_file
|
|
48
33
|
@history = Hash.new
|
|
49
34
|
@logger = logger
|
|
50
35
|
@server_name = server_name
|
|
51
|
-
@http_proxy = http_proxy
|
|
52
|
-
@https_proxy = https_proxy
|
|
53
36
|
@plugin_plan = []
|
|
54
37
|
@plugins_with_signature_errors = []
|
|
55
38
|
@directives = {} # take_snapshots, interval, sleep_interval
|
|
39
|
+
@streamer_command = nil
|
|
56
40
|
@new_plan = false
|
|
57
41
|
@local_plugin_path = File.dirname(history_file) # just put overrides and ad-hoc plugins in same directory as history file.
|
|
58
42
|
@plugin_config_path = File.join(@local_plugin_path, "plugins.properties")
|
|
@@ -68,6 +52,7 @@ module Scout
|
|
|
68
52
|
end
|
|
69
53
|
|
|
70
54
|
def refresh?
|
|
55
|
+
#info "called refresh: ping_key=#{ping_key}"
|
|
71
56
|
return true if !ping_key or account_public_key_changed? # fetch the plan again if the account key is modified/created
|
|
72
57
|
|
|
73
58
|
url=URI.join( @server.sub("https://","http://"), "/clients/#{ping_key}/ping.scout")
|
|
@@ -77,6 +62,8 @@ module Scout
|
|
|
77
62
|
headers["If-Modified-Since"] = @history["plan_last_modified"]
|
|
78
63
|
end
|
|
79
64
|
get(url, "Could not ping #{url} for refresh info", headers) do |res|
|
|
65
|
+
info "inside 'refresh?' #{res.to_hash.to_json}"
|
|
66
|
+
@streamer_command = res["x-streamer-command"] # usually will be nil, but can be [start,abcd,1234,5678|stop]
|
|
80
67
|
if res.is_a?(Net::HTTPNotModified)
|
|
81
68
|
return false
|
|
82
69
|
else
|
|
@@ -107,7 +94,6 @@ module Scout
|
|
|
107
94
|
if res["Content-Encoding"] == "gzip" and body and not body.empty?
|
|
108
95
|
body = Zlib::GzipReader.new(StringIO.new(body)).read
|
|
109
96
|
end
|
|
110
|
-
|
|
111
97
|
body_as_hash = JSON.parse(body)
|
|
112
98
|
|
|
113
99
|
temp_plugins=Array(body_as_hash["plugins"])
|
|
@@ -152,7 +138,6 @@ module Scout
|
|
|
152
138
|
|
|
153
139
|
@new_plan = true # used in determination if we should checkin this time or not
|
|
154
140
|
|
|
155
|
-
|
|
156
141
|
# Add local plugins to the plan.
|
|
157
142
|
@plugin_plan += get_local_plugins
|
|
158
143
|
rescue Exception =>e
|
|
@@ -165,6 +150,7 @@ module Scout
|
|
|
165
150
|
@plugin_plan = Array(@history["old_plugins"])
|
|
166
151
|
@plugin_plan += get_local_plugins
|
|
167
152
|
@directives = @history["directives"] || Hash.new
|
|
153
|
+
|
|
168
154
|
end
|
|
169
155
|
@plugin_plan.reject! { |p| p['code'].nil? }
|
|
170
156
|
end
|
|
@@ -245,7 +231,7 @@ module Scout
|
|
|
245
231
|
def time_to_checkin?
|
|
246
232
|
@history['last_checkin'] == nil ||
|
|
247
233
|
@directives['interval'] == nil ||
|
|
248
|
-
(Time.now.to_i - Time.at(@history['last_checkin']).to_i).abs+15
|
|
234
|
+
(Time.now.to_i - Time.at(@history['last_checkin']).to_i).abs+15 > @directives['interval'].to_i*60
|
|
249
235
|
rescue
|
|
250
236
|
debug "Failed to calculate time_to_checkin. @history['last_checkin']=#{@history['last_checkin']}. "+
|
|
251
237
|
"@directives['interval']=#{@directives['interval']}. Time.now.to_i=#{Time.now.to_i}"
|
|
@@ -495,7 +481,7 @@ module Scout
|
|
|
495
481
|
contents=File.read(@history_file)
|
|
496
482
|
begin
|
|
497
483
|
@history = YAML.load(contents)
|
|
498
|
-
rescue
|
|
484
|
+
rescue => e
|
|
499
485
|
backup_path=File.join(File.dirname(@history_file), "history.corrupt")
|
|
500
486
|
info "Couldn't parse the history file. Deleting it and resetting to an empty history file. Keeping a backup at #{backup_path}"
|
|
501
487
|
File.open(backup_path,"w"){|f|f.write contents}
|
|
@@ -540,70 +526,6 @@ module Scout
|
|
|
540
526
|
}
|
|
541
527
|
end
|
|
542
528
|
|
|
543
|
-
def urlify(url_name, options = Hash.new)
|
|
544
|
-
return unless @server
|
|
545
|
-
options.merge!(:client_version => Scout::VERSION)
|
|
546
|
-
URI.join( @server,
|
|
547
|
-
"/clients/CLIENT_KEY/#{url_name}.scout".
|
|
548
|
-
gsub(/\bCLIENT_KEY\b/, @client_key).
|
|
549
|
-
gsub(/\b[A-Z_]+\b/) { |k| options[k.downcase.to_sym] || k } )
|
|
550
|
-
end
|
|
551
|
-
|
|
552
|
-
def post(url, error, body, headers = Hash.new, &response_handler)
|
|
553
|
-
return unless url
|
|
554
|
-
request(url, response_handler, error) do |connection|
|
|
555
|
-
post = Net::HTTP::Post.new( url.path +
|
|
556
|
-
(url.query ? ('?' + url.query) : ''),
|
|
557
|
-
HTTP_HEADERS.merge(headers) )
|
|
558
|
-
post.body = body
|
|
559
|
-
connection.request(post)
|
|
560
|
-
end
|
|
561
|
-
end
|
|
562
|
-
|
|
563
|
-
def get(url, error, headers = Hash.new, &response_handler)
|
|
564
|
-
return unless url
|
|
565
|
-
request(url, response_handler, error) do |connection|
|
|
566
|
-
connection.get( url.path + (url.query ? ('?' + url.query) : ''),
|
|
567
|
-
HTTP_HEADERS.merge(headers) )
|
|
568
|
-
end
|
|
569
|
-
end
|
|
570
|
-
|
|
571
|
-
def request(url, response_handler, error, &connector)
|
|
572
|
-
response = nil
|
|
573
|
-
Timeout.timeout(5 * 60, APITimeoutError) do
|
|
574
|
-
|
|
575
|
-
# take care of http/https proxy, if specified in command line options
|
|
576
|
-
# Given a blank string, the proxy_uri URI instance's host/port/user/pass will be nil
|
|
577
|
-
# Net::HTTP::Proxy returns a regular Net::HTTP class if the first argument (host) is nil
|
|
578
|
-
proxy_uri = URI.parse(url.is_a?(URI::HTTPS) ? @https_proxy : @http_proxy)
|
|
579
|
-
http=Net::HTTP::Proxy(proxy_uri.host,proxy_uri.port,proxy_uri.user,proxy_uri.port).new(url.host, url.port)
|
|
580
|
-
|
|
581
|
-
if url.is_a? URI::HTTPS
|
|
582
|
-
http.use_ssl = true
|
|
583
|
-
http.ca_file = File.join( File.dirname(__FILE__),
|
|
584
|
-
*%w[.. .. data cacert.pem] )
|
|
585
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_PEER |
|
|
586
|
-
OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
|
|
587
|
-
end
|
|
588
|
-
response = no_warnings { http.start(&connector) }
|
|
589
|
-
end
|
|
590
|
-
case response
|
|
591
|
-
when Net::HTTPSuccess, Net::HTTPNotModified
|
|
592
|
-
response_handler[response] unless response_handler.nil?
|
|
593
|
-
else
|
|
594
|
-
error = "Server says: #{response['x-scout-msg']}" if response['x-scout-msg']
|
|
595
|
-
fatal error
|
|
596
|
-
raise SystemExit.new(error)
|
|
597
|
-
end
|
|
598
|
-
rescue Timeout::Error
|
|
599
|
-
fatal "Request timed out."
|
|
600
|
-
exit
|
|
601
|
-
rescue Exception
|
|
602
|
-
raise if $!.is_a? SystemExit
|
|
603
|
-
fatal "An HTTP error occurred: #{$!.message}"
|
|
604
|
-
exit
|
|
605
|
-
end
|
|
606
|
-
|
|
607
529
|
def checkin
|
|
608
530
|
debug """
|
|
609
531
|
#{PP.pp(@checkin, '')}
|
|
@@ -626,23 +548,6 @@ module Scout
|
|
|
626
548
|
end
|
|
627
549
|
|
|
628
550
|
|
|
629
|
-
def no_warnings
|
|
630
|
-
old_verbose = $VERBOSE
|
|
631
|
-
$VERBOSE = false
|
|
632
|
-
yield
|
|
633
|
-
ensure
|
|
634
|
-
$VERBOSE = old_verbose
|
|
635
|
-
end
|
|
636
|
-
|
|
637
|
-
# Forward Logger methods to an active instance, when there is one.
|
|
638
|
-
def method_missing(meth, *args, &block)
|
|
639
|
-
if (Logger::SEV_LABEL - %w[ANY]).include? meth.to_s.upcase
|
|
640
|
-
@logger.send(meth, *args, &block) unless @logger.nil?
|
|
641
|
-
else
|
|
642
|
-
super
|
|
643
|
-
end
|
|
644
|
-
end
|
|
645
|
-
|
|
646
551
|
private
|
|
647
552
|
|
|
648
553
|
# Called during initialization; loads the plugin_configs (local plugin configurations for passwords, etc)
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
require "net/https"
|
|
2
|
+
require "uri"
|
|
3
|
+
require "yaml"
|
|
4
|
+
require "timeout"
|
|
5
|
+
require "stringio"
|
|
6
|
+
require "zlib"
|
|
7
|
+
require "socket"
|
|
8
|
+
require "base64"
|
|
9
|
+
|
|
10
|
+
module Scout
|
|
11
|
+
class ServerBase
|
|
12
|
+
# A new class for plugin Timeout errors.
|
|
13
|
+
class PluginTimeoutError < RuntimeError; end
|
|
14
|
+
# A new class for API Timeout errors.
|
|
15
|
+
class APITimeoutError < RuntimeError; end
|
|
16
|
+
|
|
17
|
+
# Headers passed up with all API requests.
|
|
18
|
+
HTTP_HEADERS = { "Client-Version" => Scout::VERSION,
|
|
19
|
+
"Client-Hostname" => Socket.gethostname,
|
|
20
|
+
"Accept-Encoding" => "gzip" }
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def urlify(url_name, options = Hash.new)
|
|
26
|
+
return unless @server
|
|
27
|
+
options.merge!(:client_version => Scout::VERSION)
|
|
28
|
+
URI.join(@server,
|
|
29
|
+
"/clients/CLIENT_KEY/#{url_name}.scout".
|
|
30
|
+
gsub(/\bCLIENT_KEY\b/, @client_key).
|
|
31
|
+
gsub(/\b[A-Z_]+\b/) { |k| options[k.downcase.to_sym] || k })
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def post(url, error, body, headers = Hash.new, &response_handler)
|
|
35
|
+
return unless url
|
|
36
|
+
request(url, response_handler, error) do |connection|
|
|
37
|
+
post = Net::HTTP::Post.new(url.path +
|
|
38
|
+
(url.query ? ('?' + url.query) : ''),
|
|
39
|
+
HTTP_HEADERS.merge(headers))
|
|
40
|
+
post.body = body
|
|
41
|
+
connection.request(post)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def get(url, error, headers = Hash.new, &response_handler)
|
|
46
|
+
return unless url
|
|
47
|
+
request(url, response_handler, error) do |connection|
|
|
48
|
+
connection.get(url.path + (url.query ? ('?' + url.query) : ''),
|
|
49
|
+
HTTP_HEADERS.merge(headers))
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def request(url, response_handler, error, &connector)
|
|
54
|
+
response = nil
|
|
55
|
+
Timeout.timeout(5 * 60, APITimeoutError) do
|
|
56
|
+
http = Net::HTTP.new(url.host, url.port)
|
|
57
|
+
if url.is_a? URI::HTTPS
|
|
58
|
+
http.use_ssl = true
|
|
59
|
+
http.ca_file = File.join(File.dirname(__FILE__),
|
|
60
|
+
*%w[.. .. data cacert.pem])
|
|
61
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER |
|
|
62
|
+
OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
|
|
63
|
+
end
|
|
64
|
+
response = no_warnings { http.start(&connector) }
|
|
65
|
+
end
|
|
66
|
+
case response
|
|
67
|
+
when Net::HTTPSuccess, Net::HTTPNotModified
|
|
68
|
+
response_handler[response] unless response_handler.nil?
|
|
69
|
+
else
|
|
70
|
+
error = "Server says: #{response['x-scout-msg']}" if response['x-scout-msg']
|
|
71
|
+
fatal error
|
|
72
|
+
raise SystemExit.new(error)
|
|
73
|
+
end
|
|
74
|
+
rescue Timeout::Error
|
|
75
|
+
fatal "Request timed out."
|
|
76
|
+
exit
|
|
77
|
+
rescue Exception
|
|
78
|
+
raise if $!.is_a? SystemExit
|
|
79
|
+
fatal "An HTTP error occurred: #{$!.message}"
|
|
80
|
+
exit
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def no_warnings
|
|
84
|
+
old_verbose = $VERBOSE
|
|
85
|
+
$VERBOSE = false
|
|
86
|
+
yield
|
|
87
|
+
ensure
|
|
88
|
+
$VERBOSE = old_verbose
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Forward Logger methods to an active instance, when there is one.
|
|
92
|
+
def method_missing(meth, *args, &block)
|
|
93
|
+
if (Logger::SEV_LABEL - %w[ANY]).include? meth.to_s.upcase
|
|
94
|
+
@logger.send(meth, *args, &block) unless @logger.nil?
|
|
95
|
+
else
|
|
96
|
+
super
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'json'
|
|
3
|
+
|
|
4
|
+
module Scout
|
|
5
|
+
class Streamer < Scout::ServerBase
|
|
6
|
+
MAX_DURATION = 60*30 # will shut down automatically after this many seconds
|
|
7
|
+
SLEEP = 1
|
|
8
|
+
|
|
9
|
+
# * history_file is the *path* to the history file
|
|
10
|
+
# * plugin_ids is an array of integers
|
|
11
|
+
def initialize(server, client_key, history_file, plugin_ids, streaming_key, logger = nil)
|
|
12
|
+
@server = server
|
|
13
|
+
@client_key = client_key
|
|
14
|
+
@history_file = history_file
|
|
15
|
+
@history = Hash.new
|
|
16
|
+
@logger = logger
|
|
17
|
+
|
|
18
|
+
@plugins = []
|
|
19
|
+
|
|
20
|
+
Pusher.app_id = '11495'
|
|
21
|
+
Pusher.key = 'a95aa7293cd158100246'
|
|
22
|
+
Pusher.secret = '9c13ccfe325fe3ae682d'
|
|
23
|
+
|
|
24
|
+
debug "plugin_ids = #{plugin_ids.inspect}"
|
|
25
|
+
debug "streaming_key = #{streaming_key}"
|
|
26
|
+
|
|
27
|
+
streamer_start_time = Time.now
|
|
28
|
+
|
|
29
|
+
hostname=Socket.gethostname
|
|
30
|
+
# load history
|
|
31
|
+
load_history
|
|
32
|
+
|
|
33
|
+
# get the array of plugins, AKA the plugin plan
|
|
34
|
+
@plugin_plan = Array(@history["old_plugins"])
|
|
35
|
+
|
|
36
|
+
# iterate through the plan and compile each plugin. We only compile plugins once at the beginning of the run
|
|
37
|
+
@plugin_plan.each do |plugin|
|
|
38
|
+
begin
|
|
39
|
+
compile_plugin(plugin) # this is what adds to the @plugin array
|
|
40
|
+
rescue Exception
|
|
41
|
+
error("Encountered an error: #{$!.message}")
|
|
42
|
+
puts $!.backtrace.join('\n')
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# main loop. Continue running until global $continue_streaming is set to false OR we've been running for MAX DURATION
|
|
47
|
+
while(streamer_start_time+MAX_DURATION > Time.now && $continue_streaming) do
|
|
48
|
+
plugins=[]
|
|
49
|
+
@plugins.each_with_index do |plugin,i|
|
|
50
|
+
# ignore plugins whose ids are not in the plugin_ids array -- this also ignores local plugins
|
|
51
|
+
next if !(@plugin_plan[i]['id'] && plugin_ids.include?(@plugin_plan[i]['id'].to_i))
|
|
52
|
+
start_time=Time.now
|
|
53
|
+
plugin.reset!
|
|
54
|
+
plugin.run
|
|
55
|
+
duration=((Time.now-start_time)*1000).to_i
|
|
56
|
+
|
|
57
|
+
plugins << {:duration=>duration,
|
|
58
|
+
:fields=>plugin.reports.inject{|memo,hash|memo.merge(hash)},
|
|
59
|
+
:name=>@plugin_plan[i]["name"],
|
|
60
|
+
:id=>@plugin_plan[i]["id"]}
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
bundle={:hostname=>hostname,
|
|
64
|
+
:server_time=>Time.now.strftime("%I:%M:%S %p"),
|
|
65
|
+
:num_processes=>`ps -e | wc -l`.chomp.to_i,
|
|
66
|
+
:plugins=>plugins }
|
|
67
|
+
|
|
68
|
+
begin
|
|
69
|
+
Pusher[streaming_key].trigger!('server_data', bundle)
|
|
70
|
+
rescue Pusher::Error => e
|
|
71
|
+
# (Pusher::AuthenticationError, Pusher::HTTPError, or Pusher::Error)
|
|
72
|
+
error "Error pushing data: #{e.message}"
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
if false
|
|
76
|
+
# debugging
|
|
77
|
+
File.open(File.join(File.dirname(@history_file),"debug.txt"),"w") do |f|
|
|
78
|
+
f.puts "... sleeping @ #{Time.now.strftime("%I:%M:%S %p")}..."
|
|
79
|
+
f.puts bundle.to_yaml
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
sleep(SLEEP)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
private
|
|
89
|
+
|
|
90
|
+
#def post_bundle(bundle)
|
|
91
|
+
# post( urlify(:stream),
|
|
92
|
+
# "Unable to stream to server.",
|
|
93
|
+
# bundle.to_json,
|
|
94
|
+
# "Content-Type" => "application/json")
|
|
95
|
+
#rescue Exception
|
|
96
|
+
# error "Unable to stream to server."
|
|
97
|
+
# debug $!.class.to_s
|
|
98
|
+
# debug $!.message
|
|
99
|
+
# debug $!.backtrace.join("\n")
|
|
100
|
+
#end
|
|
101
|
+
|
|
102
|
+
# sets up the @plugins array
|
|
103
|
+
def compile_plugin(plugin)
|
|
104
|
+
plugin_id = plugin['id']
|
|
105
|
+
|
|
106
|
+
# take care of plugin overrides
|
|
107
|
+
local_path = File.join(File.dirname(@history_file), "#{plugin_id}.rb")
|
|
108
|
+
if File.exist?(local_path)
|
|
109
|
+
code_to_run = File.read(local_path)
|
|
110
|
+
else
|
|
111
|
+
code_to_run=plugin['code'] || ""
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
id_and_name = "#{plugin['id']}-#{plugin['name']}".sub(/\A-/, "")
|
|
115
|
+
last_run = @history["last_runs"][id_and_name] ||
|
|
116
|
+
@history["last_runs"][plugin['name']]
|
|
117
|
+
memory = @history["memory"][id_and_name] ||
|
|
118
|
+
@history["memory"][plugin['name']]
|
|
119
|
+
options=(plugin['options'] || Hash.new)
|
|
120
|
+
options.merge!(:tuner_days=>"")
|
|
121
|
+
code_class=Plugin.extract_code_class(code_to_run)
|
|
122
|
+
begin
|
|
123
|
+
eval(code_to_run, TOPLEVEL_BINDING, plugin['path'] || plugin['name'] )
|
|
124
|
+
klass=Plugin.const_get(code_class)
|
|
125
|
+
info "Added a #{klass.name} plugin, id = #{plugin_id}"
|
|
126
|
+
@plugins << klass.load(last_run, (memory || Hash.new), options)
|
|
127
|
+
|
|
128
|
+
# turn certain methods into null-ops, so summaries aren't generated. Note that this is ad-hoc, and not future-proof.
|
|
129
|
+
if klass.name=="RailsRequests"; def klass.analyze;end;end
|
|
130
|
+
if klass.name=="ApacheAnalyzer"; def klass.generate_log_analysis;end;end
|
|
131
|
+
|
|
132
|
+
rescue Exception
|
|
133
|
+
error "Plugin would not compile: #{$!.message}"
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def load_history
|
|
139
|
+
begin
|
|
140
|
+
debug "Loading history file..."
|
|
141
|
+
contents=File.read(@history_file)
|
|
142
|
+
@history = YAML.load(contents)
|
|
143
|
+
rescue => e
|
|
144
|
+
info "Couldn't load or parse the history file at #{@history_file}. Exiting."
|
|
145
|
+
exit(1)
|
|
146
|
+
end
|
|
147
|
+
info "History file loaded."
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# Forward Logger methods to an active instance, when there is one.
|
|
151
|
+
def method_missing(meth, *args, &block)
|
|
152
|
+
if (Logger::SEV_LABEL - %w[ANY]).include? meth.to_s.upcase
|
|
153
|
+
@logger.send(meth, *args, &block) unless @logger.nil?
|
|
154
|
+
else
|
|
155
|
+
super
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def growl(message)`growlnotify -m '#{message.gsub("'","\'")}'`;end
|
|
160
|
+
|
|
161
|
+
end
|
|
162
|
+
end
|