forked from flapjack/flapjack
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathprofile.rake
228 lines (182 loc) · 6.67 KB
/
profile.rake
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
namespace :profile do
require 'fileutils'
require 'flapjack/configuration'
require 'ruby-prof'
FLAPJACK_ROOT = File.join(File.dirname(__FILE__), '..')
FLAPJACK_CONFIG = File.join(FLAPJACK_ROOT, 'etc', 'flapjack_profile_config.toml')
FLAPJACK_PROFILER = ENV['FLAPJACK_PROFILER'] || 'rubyprof'
port = ENV['FLAPJACK_PROFILER'].to_i
FLAPJACK_PORT = ((port > 1024) && (port <= 65535)) ? port : 8075
REPETITIONS = 10
def profile_pikelet(type, config, redis_options)
require 'flapjack/redis_proxy'
require 'flapjack/pikelet'
Flapjack::RedisProxy.config = redis_options
check_db_empty(:redis => redis_options)
setup_baseline_data
@monitor = Monitor.new
@cond = @monitor.new_cond
@status = 'uninitialized'
RubyProf.start
Thread.new do
@monitor.synchronize do
@cond.wait_until { @status == 'initialized' }
yield
@status = 'finished'
@cond.signal
end
# redis connections are thread-local, so quitting at the end of each thread
Flapjack.redis.quit
end
pikelets = Flapjack::Pikelet.create(type, nil, :config => config)
@monitor.synchronize do
pikelets.each do |pik|
pik.start
end
# give webrick some time to start
sleep(3) if 'web'.eql?(type)
@status = 'initialized'
@cond.signal
@cond.wait_until { @status == 'finished' }
end
pikelets.each do |pik|
pik.stop
end
result = RubyProf.stop
Flapjack.redis.flushdb
Flapjack.redis.quit
# result.eliminate_methods!([/Mutex/])
printer = RubyProf::MultiPrinter.new(result)
output_dir = File.join('tmp', 'profiles')
FileUtils.mkdir_p(output_dir)
printer.print(:path => output_dir, :profile => type)
end
# ### utility methods
def load_config
config = Flapjack::Configuration.new
config.load(FLAPJACK_CONFIG)
config_env = config.all
if config_env.nil? || config_env.empty?
puts "No config data found in '#{FLAPJACK_CONFIG}'"
exit(false)
end
return config_env, config.for_redis
end
def check_db_empty(options = {})
# DBSIZE can return > 0 with expired keys -- but that's fine, we only
# want to run against an explicitly empty DB. If this fails against the
# intended Redis DB, the user can FLUSHDB it manually
db_size = Flapjack.redis.dbsize.to_i
if db_size > 0
db = options[:redis]['db']
puts "The Redis database has a non-zero DBSIZE (#{db_size}) -- "
"profiling will destroy data. Use 'SELECT #{db}; FLUSHDB' in " +
'redis-cli if you want to profile using this database.'
puts "[redis options] #{options[:redis].inspect}\nExiting..."
exit(false)
end
end
# # this adds a default entity and contact, so that the profiling methods
# # will actually trigger enough code to be useful
def setup_baseline_data(options = {})
entity = Flapjack::Data::Entity.new(:id => "2000", :name => "clientx-app-01")
entity.save
contact = Flapjack::Data::Contact.new(:id => '1000',
:name => 'John Smith')
contact.save
medium = Flapjack::Data::Medium.new(:type => 'email', :address => '[email protected]',
:interval => 30)
medium.save
contact.media << medium
entity.contacts << contact
end
def message_contents
contact = Flapjack::Data::Contact.find_by_id('1000')
{'notification_type' => 'problem',
'contact_name' => contact.name,
'address' => contact.media.intersect(:type => 'email').all.first.address,
'state' => 'critical',
'state_duration' => 23,
'summary' => '',
'last_state' => 'ok',
'last_summary' => 'profiling',
'details' => 'Profiling!',
'time' => Time.now.to_i,
'event_id' => 'clientx-app-01:ping'}
end
def profile_message_gateway(type, queue)
config_env, redis_options = load_config
profile_pikelet(type, config_env['gateways'][type], redis_options) do
begin
msg_contents = message_contents
REPETITIONS.times do |n|
msg_contents['event_count'] = n
Flapjack.redis.lpush(queue, Flapjack.dump_json(msg_contents))
Flapjack.redis.lpush("#{queue}_actions", "+")
end
rescue => e
puts e.message
puts e.backtrace.join("\n")
end
end
end
# ## end utility methods
desc "profile processor with rubyprof"
task :processor do
require 'flapjack/processor'
require 'flapjack/data/event'
FLAPJACK_ENV = ENV['FLAPJACK_ENV'] || 'profile'
config_env, redis_options = load_config
profile_pikelet('processor', config_env['processor'], redis_options) do
REPETITIONS.times do |n|
Flapjack::Data::Event.push('events', {'entity' => 'clientx-app-01',
'check' => 'ping',
'type' => 'service',
'state' => (n ? 'ok' : 'critical'),
'summary' => 'testing'})
end
end
end
# # NB: you'll need to access a real jabber server for this; if external events
# # come in from that then runs will not be comparable
desc "profile jabber gateway with rubyprof"
task :jabber do
require 'flapjack/data/contact'
require 'flapjack/data/event'
require 'flapjack/data/notification'
require 'flapjack/gateways/jabber'
FLAPJACK_ENV = ENV['FLAPJACK_ENV'] || 'profile'
profile_message_gateway('jabber', config_env['gateways']['jabber']['queue'])
end
# NB: you'll need an external email server set up for this (whether it's
# mailtrap or a real server)
desc "profile email notifier with rubyprof"
task :email do
require 'flapjack/data/contact'
require 'flapjack/data/event'
require 'flapjack/data/notification'
require 'flapjack/gateways/email'
FLAPJACK_ENV = ENV['FLAPJACK_ENV'] || 'profile'
profile_message_gateway('email', config_env['gateways']['email']['queue'])
end
# Of course, if external requests come to this server then different runs will
# not be comparable
desc "profile web server with rubyprof"
task :web do
require 'net/http'
require 'flapjack/gateways/web'
FLAPJACK_ENV = ENV['FLAPJACK_ENV'] || 'profile'
config_env, redis_options = load_config
profile_pikelet('web', config_env['gateways']['web'], redis_options) {
uri = URI.parse("http://127.0.0.1:#{FLAPJACK_PORT}/")
REPETITIONS.times do |n|
begin
response = Net::HTTP.get(uri)
rescue => e
puts e.message
puts e.backtrace.join("\n")
end
end
}
end
end