rackamole 0.0.9 → 0.1.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/Rakefile +1 -1
- data/lib/rackamole/alert/twitt.rb +12 -3
- data/lib/rackamole/mole.rb +84 -41
- data/lib/rackamole/stash/base.rb +25 -0
- data/lib/rackamole/stash/collector.rb +93 -0
- data/lib/rackamole/stash/fault.rb +10 -0
- data/lib/rackamole/stash/perf.rb +10 -0
- data/lib/rackamole/store/mongo_db.rb +11 -9
- data/lib/rackamole.rb +1 -1
- data/samples/rails/moled/app/controllers/fred_controller.rb +1 -0
- data/samples/rails/moled/config/environment.rb +8 -1
- data/samples/rails/moled/log/development.log +20 -0
- data/samples/rails/moled/log/production.log +10 -0
- data/samples/sinatra/moled.rb +34 -12
- data/samples/sinatra/public/.DS_Store +0 -0
- data/samples/sinatra/public/images/mole_logo.png +0 -0
- data/samples/sinatra/public/stylesheets/styles.css +58 -0
- data/samples/sinatra/views/index.erb +14 -0
- data/samples/sinatra/views/layout.erb +23 -0
- data/samples/sinatra/views/params.erb +1 -1
- data/samples/sinatra/views/post.erb +1 -0
- data/samples/sinatra/views/slow.erb +1 -0
- data/spec/rackamole/alert/twitt_spec.rb +21 -8
- data/spec/rackamole/mole_spec.rb +221 -46
- data/spec/rackamole/stash/collector_spec.rb +64 -0
- data/spec/rackamole/stash/fault_spec.rb +20 -0
- data/spec/rackamole/stash/perf_spec.rb +16 -0
- data/spec/rackamole/store/mongo_db_spec.rb +1 -0
- data/{lib/rackamole/config.rb → z_experiments/configuration.rb} +0 -0
- metadata +27 -4
- data/samples/sinatra/blee.rb +0 -7
data/Rakefile
CHANGED
@@ -28,6 +28,6 @@ PROJ.rcov.opts = ["--sort", "coverage", "-T", '-x mongo']
|
|
28
28
|
depend_on "logging" , ">= 1.2.2"
|
29
29
|
depend_on "hitimes" , ">= 1.0.3"
|
30
30
|
depend_on "mongo" , ">= 0.17.1"
|
31
|
-
|
31
|
+
depend_on "chronic" , ">= 0.2.3"
|
32
32
|
depend_on "twitter4r" , ">= 0.3.0"
|
33
33
|
depend_on "actionmailer" , ">= 2.1.0"
|
@@ -4,7 +4,13 @@ module Rackamole::Alert
|
|
4
4
|
# Leverage twitter as a notification client. You can setup a private twitter account
|
5
5
|
# and have your moled app twitt exception/perf alerts...
|
6
6
|
class Twitt
|
7
|
-
|
7
|
+
|
8
|
+
# Twitt an alert
|
9
|
+
def self.deliver_alert( username, password, attrs )
|
10
|
+
@twitt ||= Twitt.new( username, password )
|
11
|
+
@twitt.send_alert( attrs )
|
12
|
+
end
|
13
|
+
|
8
14
|
# This class is used to send out moled twitter notification. This feature is enabled
|
9
15
|
# by setting both :twitter_auth and twitt_on options on the Rack::Mole. When a moled
|
10
16
|
# feature comes around it will be twitted on your configured account. This allow your
|
@@ -41,8 +47,11 @@ module Rackamole::Alert
|
|
41
47
|
when Rackamole.perf : "[Perf] #{twitt_msg}\n#{format_time(args[:request_time])} secs"
|
42
48
|
when Rackamole.fault : "[Fault] #{twitt_msg}\n#{args[:fault]}"
|
43
49
|
else nil
|
44
|
-
end
|
45
|
-
|
50
|
+
end
|
51
|
+
if twitt_msg
|
52
|
+
twitt_msg += " - #{args[:created_at].strftime( "%H:%M:%S")}"
|
53
|
+
twitt.status( :post, truncate( twitt_msg ) )
|
54
|
+
end
|
46
55
|
twitt_msg
|
47
56
|
rescue => boom
|
48
57
|
$stderr.puts "TWITT mole failed with #{boom}"
|
data/lib/rackamole/mole.rb
CHANGED
@@ -17,10 +17,18 @@ module Rack
|
|
17
17
|
# === Options
|
18
18
|
#
|
19
19
|
# :app_name :: The name of the application (Default: Moled App)
|
20
|
+
# :log_level :: Rackamole logger level. (Default: info )
|
20
21
|
# :environment :: The environment for the application ie :environment => RAILS_ENV
|
21
22
|
# :perf_threshold :: Any request taking longer than this value will get moled. Default: 10secs
|
22
23
|
# :moleable :: Enable/Disable the MOle (Default:true)
|
23
24
|
# :store :: The storage instance ie log file or mongodb [Default:stdout]
|
25
|
+
# :expiration :: Number of seconds to expiration. The mole will not keep sending alert if a particular
|
26
|
+
# mole type has been reported in the past. This threshold specifies the limit at which
|
27
|
+
# the previously sent alerts will expire and thus will be sent again.
|
28
|
+
# For instance, it might be the case that the app is consistently slow for a particular action.
|
29
|
+
# On the first encounter an alert will be sent ( if configured ). Any subsequent requests for this action
|
30
|
+
# will not fire an alert until the expiration threshold is hit. The default is 1 hour.
|
31
|
+
# Setting this threshold to Rackamole::Stash::Collector::NEVER will result in alerts being fired continually.
|
24
32
|
# :user_key :: If sessions are enable, this represents the session key for the user name or
|
25
33
|
# user_id.
|
26
34
|
# ==
|
@@ -46,18 +54,22 @@ module Rack
|
|
46
54
|
# :email => { :from => 'fred@acme.com', :to => ['blee@acme.com', 'doh@acme.com'], :alert_on => [Rackamole.perf, Rackamole.fault] }
|
47
55
|
# ==
|
48
56
|
#
|
49
|
-
def initialize( app, opts={} )
|
50
|
-
@app
|
57
|
+
def initialize( app, opts={} )
|
58
|
+
@app = app
|
51
59
|
init_options( opts )
|
52
60
|
validate_options
|
61
|
+
@logger = Rackamole::Logger.new( :logger_name => 'RACKAMOLE', :log_level => options[:log_level] )
|
53
62
|
end
|
54
63
|
|
55
64
|
# Entering the MOle zone...
|
56
65
|
# Watches incoming requests and report usage information. The mole will also track request that
|
57
66
|
# are taking longer than expected and also report any requests that are raising exceptions.
|
58
|
-
def call( env )
|
67
|
+
def call( env )
|
59
68
|
# Bail if application is not moleable
|
60
69
|
return @app.call( env ) unless moleable?
|
70
|
+
|
71
|
+
@stash = env['mole.stash'] if env['mole.stash']
|
72
|
+
@stash = Rackamole::Stash::Collector.new( options[:app_name], options[:environment], options[:expiration] ) unless stash
|
61
73
|
|
62
74
|
status, headers, body = nil
|
63
75
|
elapsed = Hitimes::Interval.measure do
|
@@ -76,7 +88,7 @@ module Rack
|
|
76
88
|
# ===========================================================================
|
77
89
|
private
|
78
90
|
|
79
|
-
attr_reader :options #:nodoc:
|
91
|
+
attr_reader :options, :logger, :stash #:nodoc:
|
80
92
|
|
81
93
|
# Load up configuration options
|
82
94
|
def init_options( opts )
|
@@ -86,7 +98,9 @@ module Rack
|
|
86
98
|
# Mole default options
|
87
99
|
def default_options
|
88
100
|
{
|
89
|
-
:moleable => true,
|
101
|
+
:moleable => true,
|
102
|
+
:log_level => :info,
|
103
|
+
:expiration => 60*60, # 1 hour
|
90
104
|
:app_name => "Moled App",
|
91
105
|
:environment => 'test',
|
92
106
|
:excluded_paths => [/.?\.ico/, /.?\.png/],
|
@@ -109,24 +123,60 @@ module Rack
|
|
109
123
|
end
|
110
124
|
|
111
125
|
# Send moled info to store and potentially send out alerts...
|
112
|
-
def mole_feature( env, elapsed, status, headers, body )
|
113
|
-
|
126
|
+
def mole_feature( env, elapsed, status, headers, body )
|
127
|
+
env['mole.stash'] = stash
|
114
128
|
|
129
|
+
attrs = mole_info( env, elapsed, status, headers, body )
|
130
|
+
|
131
|
+
# If nothing to mole bail out!
|
132
|
+
return if attrs.empty?
|
133
|
+
|
115
134
|
# send info to configured store
|
116
135
|
options[:store].mole( attrs )
|
117
136
|
|
118
|
-
#
|
119
|
-
|
120
|
-
|
137
|
+
# Check for dups. If we've logged this req before don't log it again...
|
138
|
+
unless duplicated?( env, attrs )
|
139
|
+
# send email alert ?
|
140
|
+
if alertable?( :email, attrs[:type] )
|
141
|
+
logger.debug ">>> Sending out email on mole type #{attrs[:type]} to #{options[:email][:to].join( ", ")}"
|
142
|
+
Rackamole::Alert::Emole.deliver_alert( options[:email][:from], options[:email][:to], attrs )
|
143
|
+
end
|
144
|
+
|
145
|
+
# send twitter alert ?
|
146
|
+
if alertable?( :twitter, attrs[:type] )
|
147
|
+
logger.debug ">>> Sending out twitt on mole type #{attrs[:type]} on @#{options[:twitter][:username]}"
|
148
|
+
Rackamole::Alert::Twitt.deliver_alert( options[:twitter][:username], options[:twitter][:password], attrs )
|
149
|
+
end
|
150
|
+
end
|
151
|
+
rescue => boom
|
152
|
+
logger.error "!! MOLE RECORDING CRAPPED OUT !! -- #{boom}"
|
153
|
+
boom.backtrace.each { |l| logger.error l }
|
154
|
+
end
|
155
|
+
|
156
|
+
# Check if we've already seen such an error
|
157
|
+
def duplicated?( env, attrs )
|
158
|
+
# Skip features for now...
|
159
|
+
return true if attrs[:type] == Rackamole.feature
|
160
|
+
|
161
|
+
# Don't bother if expiration is set to never. ie fire alerts all the time
|
162
|
+
return false if options[:expiration] == Rackamole::Stash::Collector::NEVER
|
163
|
+
|
164
|
+
now = Time.now
|
165
|
+
app_id = [attrs[:app_name], attrs[:environment]].join( '_' )
|
166
|
+
path = attrs[:route_info] ? "#{attrs[:route_info][:controller]}#{attrs[:route_info][:action]}" : attrs[:path]
|
167
|
+
|
168
|
+
# Check expired entries
|
169
|
+
stash.expire!
|
170
|
+
|
171
|
+
# check if we've seen this error before. If so stash it.
|
172
|
+
if attrs[:type] == Rackamole.fault
|
173
|
+
return stash.stash_fault( path, attrs[:stack].first, now.utc )
|
121
174
|
end
|
122
175
|
|
123
|
-
#
|
124
|
-
if
|
125
|
-
|
176
|
+
# Check if we've seen this perf issue before. If so stash it
|
177
|
+
if attrs[:type] == Rackamole.perf
|
178
|
+
return stash.stash_perf( path, attrs[:request_time], now.utc )
|
126
179
|
end
|
127
|
-
rescue => boom
|
128
|
-
$stderr.puts "!! MOLE RECORDING CRAPPED OUT !! -- #{boom}"
|
129
|
-
boom.backtrace.each { |l| $stderr.puts l }
|
130
180
|
end
|
131
181
|
|
132
182
|
# Check if an options is set and configured
|
@@ -148,12 +198,7 @@ module Rack
|
|
148
198
|
return false unless options[filter][:alert_on]
|
149
199
|
options[filter][:alert_on].include?( type )
|
150
200
|
end
|
151
|
-
|
152
|
-
# Create or retrieve twitter client
|
153
|
-
def twitt
|
154
|
-
@twitt ||= Rackamole::Alert::Twitt.new( options[:twitter][:username], options[:twitter][:password] )
|
155
|
-
end
|
156
|
-
|
201
|
+
|
157
202
|
# Check if this request should be moled according to the exclude filters
|
158
203
|
def mole_request?( request )
|
159
204
|
options[:excluded_paths].each do |exclude_path|
|
@@ -166,9 +211,7 @@ module Rack
|
|
166
211
|
def mole_info( env, elapsed, status, headers, body )
|
167
212
|
request = Rack::Request.new( env )
|
168
213
|
info = OrderedHash.new
|
169
|
-
|
170
|
-
# dump( env )
|
171
|
-
|
214
|
+
|
172
215
|
return info unless mole_request?( request )
|
173
216
|
|
174
217
|
session = env['rack.session']
|
@@ -206,6 +249,7 @@ module Rack
|
|
206
249
|
info[:method] = env['REQUEST_METHOD']
|
207
250
|
info[:path] = request.path
|
208
251
|
info[:route_info] = route if route
|
252
|
+
info[:created_at] = Time.now.utc
|
209
253
|
|
210
254
|
# Dump request params
|
211
255
|
unless request.params.empty?
|
@@ -261,28 +305,27 @@ module Rack
|
|
261
305
|
# Fetch route info if any...
|
262
306
|
def get_route( request )
|
263
307
|
return nil unless defined?( RAILS_ENV )
|
264
|
-
|
265
308
|
# Check for invalid route exception...
|
266
309
|
begin
|
267
310
|
return ::ActionController::Routing::Routes.recognize_path( request.path, {:method => request.request_method.downcase.to_sym } )
|
268
|
-
rescue
|
311
|
+
rescue => boom
|
269
312
|
return nil
|
270
313
|
end
|
271
314
|
end
|
272
315
|
|
273
|
-
# Dump env to stdout
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
316
|
+
# Debug - Dump env to stdout
|
317
|
+
def dump( env, level=0 )
|
318
|
+
env.keys.sort{ |a,b| a.to_s <=> b.to_s }.each do |k|
|
319
|
+
value = env[k]
|
320
|
+
if value.respond_to?(:each_pair)
|
321
|
+
puts "%s %-#{40-level}s" % [' '*level,k]
|
322
|
+
dump( env[k], level+1 )
|
323
|
+
elsif value.instance_of?(::ActionController::Request) or value.instance_of?(::ActionController::Response)
|
324
|
+
puts "%s %-#{40-level}s %s" % [ ' '*level, k, value.class ]
|
325
|
+
else
|
326
|
+
puts "%s %-#{40-level}s %s" % [ ' '*level, k, value.inspect ]
|
327
|
+
end
|
328
|
+
end
|
329
|
+
end
|
287
330
|
end
|
288
331
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Rackamole::Stash
|
2
|
+
# Stash mole information into the env. These objects are meant to track
|
3
|
+
# instances of a similar event occurring in the application so that alerts
|
4
|
+
# are kept under control when shit hits the fan...
|
5
|
+
class Base
|
6
|
+
attr_reader :path, :timestamp, :count
|
7
|
+
|
8
|
+
# =======================================================================--
|
9
|
+
protected
|
10
|
+
|
11
|
+
def initialize( path, timestamp )
|
12
|
+
@path = path
|
13
|
+
@count = 1
|
14
|
+
@timestamp = timestamp
|
15
|
+
end
|
16
|
+
|
17
|
+
public
|
18
|
+
|
19
|
+
# Update count and timestamp
|
20
|
+
def update( timestamp )
|
21
|
+
@timestamp = timestamp
|
22
|
+
@count += 1
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module Rackamole::Stash
|
2
|
+
# Caches perfs and faults. If either has been seen before update their
|
3
|
+
# respective counts. This is used by the mole to track if a perf or exception
|
4
|
+
# was previously recorded.
|
5
|
+
class Collector
|
6
|
+
|
7
|
+
attr_reader :app_id
|
8
|
+
|
9
|
+
NEVER = -1
|
10
|
+
|
11
|
+
def initialize( app_name, environment, expiration=24*60*60 )
|
12
|
+
@expiration = expiration
|
13
|
+
@app_id = app_name + "_" + environment.to_s
|
14
|
+
@faults = {}
|
15
|
+
@perfs = {}
|
16
|
+
end
|
17
|
+
|
18
|
+
# Remove all entries that have expired
|
19
|
+
def expire!
|
20
|
+
expire_faults!
|
21
|
+
expire_perfs!
|
22
|
+
end
|
23
|
+
|
24
|
+
# Delete all faults older than expiration
|
25
|
+
def expire_faults!
|
26
|
+
now = Time.now
|
27
|
+
faults.each_pair do |stack, fault|
|
28
|
+
if (now - fault.timestamp) >= expiration
|
29
|
+
faults.delete( stack )
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Delete all perfs older than expiration
|
35
|
+
def expire_perfs!
|
36
|
+
now = Time.now.utc
|
37
|
+
perfs.each_pair do |path, perf|
|
38
|
+
if (now - perf.timestamp) >= expiration
|
39
|
+
perfs.delete( path )
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Log or update fault if found...
|
45
|
+
# Returns true if updated or false if created
|
46
|
+
def stash_fault( path, stack, timestamp )
|
47
|
+
fault = find_fault( path, stack )
|
48
|
+
if fault
|
49
|
+
fault.update( timestamp )
|
50
|
+
return true
|
51
|
+
end
|
52
|
+
fault = create_fault( path, stack, timestamp )
|
53
|
+
faults[stack] = fault
|
54
|
+
false
|
55
|
+
end
|
56
|
+
|
57
|
+
# Log or update performance issue if found...
|
58
|
+
# Returns true if updated or false if created
|
59
|
+
def stash_perf( path, elapsed, timestamp )
|
60
|
+
perf = find_perf( path )
|
61
|
+
if perf
|
62
|
+
perf.update( timestamp )
|
63
|
+
return true
|
64
|
+
end
|
65
|
+
perf = create_perf( path, elapsed, timestamp )
|
66
|
+
perfs[path] = perf
|
67
|
+
false
|
68
|
+
end
|
69
|
+
|
70
|
+
# =========================================================================
|
71
|
+
private
|
72
|
+
|
73
|
+
attr_reader :faults, :perfs, :expiration
|
74
|
+
|
75
|
+
def create_fault( path, stack, timestamp )
|
76
|
+
faults[stack] = Rackamole::Stash::Fault.new( path, stack, timestamp )
|
77
|
+
end
|
78
|
+
|
79
|
+
def create_perf( path, elapsed, timestamp )
|
80
|
+
perfs[path] = Rackamole::Stash::Perf.new( path, elapsed, timestamp )
|
81
|
+
end
|
82
|
+
|
83
|
+
# Check if we've seen a similar fault on this application
|
84
|
+
def find_fault( path, stack )
|
85
|
+
faults[stack]
|
86
|
+
end
|
87
|
+
|
88
|
+
# Check if we've seen this perf issue on this application
|
89
|
+
def find_perf( path )
|
90
|
+
perfs[path]
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -96,21 +96,22 @@ module Rackamole
|
|
96
96
|
row[min_field(:context)] = args.delete( :path )
|
97
97
|
end
|
98
98
|
|
99
|
-
feature = features.find_one( row )
|
100
|
-
return feature if feature
|
101
|
-
|
102
|
-
|
103
|
-
|
99
|
+
feature = features.find_one( row, :fields => ['_id'] )
|
100
|
+
return feature['_id'] if feature
|
101
|
+
|
102
|
+
row[min_field(:created_at)] = args[:created_at]
|
103
|
+
|
104
|
+
features.save( row )
|
104
105
|
end
|
105
106
|
|
106
107
|
# Insert a new feature in the db
|
107
108
|
# NOTE : Using min key to reduce storage needs. I know not that great for higher level api's :-(
|
108
109
|
# also saving date and time as ints. same deal...
|
109
|
-
def save_log(
|
110
|
-
now =
|
110
|
+
def save_log( feature_id, args )
|
111
|
+
now = args.delete( :created_at )
|
111
112
|
row = {
|
112
113
|
min_field( :type ) => args[:type],
|
113
|
-
min_field( :feature_id ) =>
|
114
|
+
min_field( :feature_id ) => feature_id.to_s,
|
114
115
|
min_field( :date_id ) => ("%4d%02d%02d" %[now.year, now.month, now.day]).to_i,
|
115
116
|
min_field( :time_id ) => ("%02d%02d%02d" %[now.hour, now.min, now.sec] ).to_i
|
116
117
|
}
|
@@ -151,7 +152,8 @@ module Rackamole
|
|
151
152
|
:params => :par,
|
152
153
|
:ruby_version => :ver,
|
153
154
|
:fault => :msg,
|
154
|
-
:stack => :sta
|
155
|
+
:stack => :sta,
|
156
|
+
:created_at => :cro
|
155
157
|
}
|
156
158
|
end
|
157
159
|
end
|
data/lib/rackamole.rb
CHANGED
@@ -9,7 +9,14 @@ require File.join(File.dirname(__FILE__), 'boot')
|
|
9
9
|
Rails::Initializer.run do |config|
|
10
10
|
|
11
11
|
require 'rackamole'
|
12
|
-
config.middleware.use Rack::Mole, {
|
12
|
+
config.middleware.use Rack::Mole, {
|
13
|
+
:app_name => "Moled Rails",
|
14
|
+
:user_key => :user_name,
|
15
|
+
:expiration => 60,
|
16
|
+
:perf_threshold => 0.2,
|
17
|
+
:twitter => { :username => 'moled', :password => 'fernand~1', :alert_on => [Rackamole.perf, Rackamole.fault] },
|
18
|
+
:user_key => :user_name
|
19
|
+
}
|
13
20
|
|
14
21
|
# Settings in config/environments/* take precedence over those specified here.
|
15
22
|
# Application configuration should go into files in config/initializers
|
@@ -78,3 +78,23 @@ Processing FredController#show (for 127.0.0.1 at 2009-11-15 11:54:08) [GET]
|
|
78
78
|
Parameters: {"id"=>"10"}
|
79
79
|
Rendering fred/show
|
80
80
|
Completed in 7ms (View: 6, DB: 0) | 200 OK [http://localhost/fred/10]
|
81
|
+
|
82
|
+
|
83
|
+
Processing FredController#index (for 127.0.0.1 at 2009-11-28 13:08:32) [GET]
|
84
|
+
Rendering fred/index
|
85
|
+
Completed in 135ms (View: 11, DB: 0) | 200 OK [http://localhost/fred]
|
86
|
+
|
87
|
+
|
88
|
+
Processing FredController#index (for 127.0.0.1 at 2009-11-28 13:08:40) [GET]
|
89
|
+
Rendering fred/index
|
90
|
+
Completed in 2ms (View: 0, DB: 0) | 200 OK [http://localhost/fred]
|
91
|
+
|
92
|
+
|
93
|
+
Processing FredController#index (for 127.0.0.1 at 2009-11-28 13:09:19) [GET]
|
94
|
+
Rendering fred/index
|
95
|
+
Completed in 1004ms (View: 2, DB: 0) | 200 OK [http://localhost/fred]
|
96
|
+
|
97
|
+
|
98
|
+
Processing FredController#index (for 127.0.0.1 at 2009-11-28 13:09:23) [GET]
|
99
|
+
Rendering fred/index
|
100
|
+
Completed in 1002ms (View: 1, DB: 0) | 200 OK [http://localhost/fred]
|
@@ -34,3 +34,13 @@ RuntimeError (Oh snap!):
|
|
34
34
|
app/controllers/fred_controller.rb:7:in `edit'
|
35
35
|
|
36
36
|
Rendering /Users/fgaliana/work/git/rackamole/samples/rails/moled/public/500.html (500 Internal Server Error)
|
37
|
+
|
38
|
+
|
39
|
+
Processing FredController#index (for 127.0.0.1 at 2009-11-28 13:10:07) [GET]
|
40
|
+
Rendering fred/index
|
41
|
+
Completed in 1003ms (View: 1, DB: 0) | 200 OK [http://localhost/fred]
|
42
|
+
|
43
|
+
|
44
|
+
Processing FredController#index (for 127.0.0.1 at 2009-11-28 13:10:11) [GET]
|
45
|
+
Rendering fred/index
|
46
|
+
Completed in 1001ms (View: 0, DB: 0) | 200 OK [http://localhost/fred]
|
data/samples/sinatra/moled.rb
CHANGED
@@ -2,34 +2,56 @@ require 'rubygems'
|
|
2
2
|
require 'sinatra'
|
3
3
|
require 'rackamole'
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
use Rack::
|
5
|
+
set :environment, :production
|
6
|
+
|
7
|
+
configure :production do
|
8
|
+
set :sessions, true
|
9
|
+
use Rack::Lint
|
10
|
+
use Rack::Session::Cookie
|
11
|
+
use Rack::Mole, {
|
12
|
+
:app_name => "Moled Franky",
|
13
|
+
:log_level => :debug,
|
14
|
+
:user_key => :user_name,
|
15
|
+
:expiration => 10,
|
16
|
+
:perf_threshold => 0.2,
|
17
|
+
:twitter => { :username => 'moled', :password => 'fernand~1', :alert_on => [Rackamole.perf, Rackamole.fault] },
|
18
|
+
:excluded_paths => [ /.+?\.css/, /.+?\.png/ ]
|
19
|
+
}
|
10
20
|
end
|
11
21
|
|
12
22
|
before do
|
13
23
|
session[:user_name] = "Fernand"
|
14
24
|
end
|
15
25
|
|
26
|
+
get '/' do
|
27
|
+
puts "Yo"
|
28
|
+
erb :index
|
29
|
+
end
|
30
|
+
|
16
31
|
get '/normal' do
|
17
|
-
@blee
|
18
|
-
session[:fred] = "
|
32
|
+
@blee = "Hello World!"
|
33
|
+
session[:fred] = "oh dear"
|
34
|
+
|
19
35
|
erb :normal
|
20
36
|
end
|
21
37
|
|
38
|
+
post '/post' do
|
39
|
+
@post = params[:blee]
|
40
|
+
erb :post
|
41
|
+
end
|
42
|
+
|
22
43
|
get '/params/:id' do
|
23
|
-
@blee
|
24
|
-
session[:
|
44
|
+
@blee = params[:id]
|
45
|
+
session[:blee] = "something interesting"
|
46
|
+
|
25
47
|
erb :params
|
26
48
|
end
|
27
49
|
|
28
50
|
get '/error' do
|
29
|
-
raise "Oh
|
51
|
+
raise "Oh Snap!"
|
30
52
|
end
|
31
53
|
|
32
54
|
get '/slow' do
|
33
|
-
sleep
|
34
|
-
|
55
|
+
sleep 0.2
|
56
|
+
erb :slow
|
35
57
|
end
|
Binary file
|
Binary file
|
@@ -0,0 +1,58 @@
|
|
1
|
+
* {
|
2
|
+
outline-color: invert;
|
3
|
+
outline-style: none;
|
4
|
+
outline-width: medium;
|
5
|
+
margin: 0px;
|
6
|
+
padding: 0px;
|
7
|
+
}
|
8
|
+
|
9
|
+
body {
|
10
|
+
font-family: "Trebuchet","Lucida Grande","Lucida Sans Unicode","bitstream vera sans","trebuchet ms","verdana";
|
11
|
+
background: #f4f4f4 repeat-x top left;
|
12
|
+
color: #ffffff;
|
13
|
+
font-size: 2em;
|
14
|
+
font-size-adjust: none;
|
15
|
+
font-stretch: normal;
|
16
|
+
font-style: normal;
|
17
|
+
font-variant: normal;
|
18
|
+
font-weight: normal;
|
19
|
+
margin: 0;
|
20
|
+
}
|
21
|
+
|
22
|
+
#overall {
|
23
|
+
margin: 0px auto;
|
24
|
+
width: 1000px;
|
25
|
+
overflow: none;
|
26
|
+
margin-top: 30px;
|
27
|
+
}
|
28
|
+
|
29
|
+
#logo {
|
30
|
+
float:left;
|
31
|
+
width:45%;
|
32
|
+
margin-bottom:10px;
|
33
|
+
}
|
34
|
+
|
35
|
+
#main {
|
36
|
+
clear: left;
|
37
|
+
margin: 20px 10px 10px 20px;
|
38
|
+
overflow: none;
|
39
|
+
}
|
40
|
+
|
41
|
+
h1 {
|
42
|
+
font-size: 2.2em;
|
43
|
+
color: #434343;
|
44
|
+
}
|
45
|
+
|
46
|
+
a {
|
47
|
+
color: #cccccc;
|
48
|
+
text-decoration: none;
|
49
|
+
}
|
50
|
+
|
51
|
+
a:hover {
|
52
|
+
text_decoration: underline;
|
53
|
+
}
|
54
|
+
|
55
|
+
input {
|
56
|
+
font-size: 1em;
|
57
|
+
color: #cccccc;
|
58
|
+
}
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<h1>Mole sampler</h1>
|
2
|
+
|
3
|
+
<ul>
|
4
|
+
<li><a href="/normal">Plain ol' get</a></li>
|
5
|
+
<li><a href="/params/10">Get with params</a></li>
|
6
|
+
<li><a href="/error">Uncaught fault</a></li>
|
7
|
+
<li><a href="/slow">Slow request</a></li>
|
8
|
+
<li>
|
9
|
+
<form action="/post" method="post" >
|
10
|
+
<input type="text" name="blee"/>
|
11
|
+
<input type="submit" value="push me"/>
|
12
|
+
</form>
|
13
|
+
</li>
|
14
|
+
</ul>
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
2
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
3
|
+
<head>
|
4
|
+
<title>R A C K A M O L E - Sampler</title>
|
5
|
+
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
6
|
+
<link rel="icon" href="/favicon.ico" type="image/x-icon"/>
|
7
|
+
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon"/>
|
8
|
+
<link rel="stylesheet" href="/stylesheets/styles.css" type="text/css" media="screen" />
|
9
|
+
</head>
|
10
|
+
|
11
|
+
<body id="body">
|
12
|
+
<div id="overall">
|
13
|
+
<div id="logo">
|
14
|
+
<a href="/">
|
15
|
+
<img src='/images/mole_logo.png' style="border:none"/>
|
16
|
+
</a>
|
17
|
+
</div>
|
18
|
+
<div id="main">
|
19
|
+
<%= yield %>
|
20
|
+
</div>
|
21
|
+
</div>
|
22
|
+
</body>
|
23
|
+
</html>
|
@@ -1 +1 @@
|
|
1
|
-
<h1>Params -- <%=@
|
1
|
+
<h1>Params -- <%=@post%></h1>
|
@@ -0,0 +1 @@
|
|
1
|
+
<h1>Posted - <%=@post%></h1>
|
@@ -0,0 +1 @@
|
|
1
|
+
<h1>I am the slow one</h1>
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), %w[.. .. spec_helper])
|
2
|
+
require 'chronic'
|
2
3
|
|
3
4
|
describe Rackamole::Alert::Twitt do
|
4
5
|
before( :each ) do
|
@@ -22,11 +23,23 @@ describe Rackamole::Alert::Twitt do
|
|
22
23
|
describe '#send_alert' do
|
23
24
|
before( :each ) do
|
24
25
|
@args = OrderedHash.new
|
25
|
-
@args[:type]
|
26
|
-
@args[:app_name]
|
27
|
-
@args[:host]
|
28
|
-
@args[:user_name]
|
29
|
-
@args[:path]
|
26
|
+
@args[:type] = Rackamole.feature
|
27
|
+
@args[:app_name] = 'Test'
|
28
|
+
@args[:host] = 'Fred'
|
29
|
+
@args[:user_name] = 'Fernand'
|
30
|
+
@args[:path] = '/blee/fred'
|
31
|
+
@args[:created_at] = Chronic.parse( "2009/11/19" )
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should twitt a feature alert using class method correctly" do
|
35
|
+
twitt = mock( Rackamole::Alert::Twitt )
|
36
|
+
client = Twitter::Client.stub!( :new )
|
37
|
+
|
38
|
+
Rackamole::Alert::Twitt.should_receive( :new ).with( 'blee', 'duh').once.and_return( twitt )
|
39
|
+
# client.should_receive( :new ).once.and_return( client )
|
40
|
+
twitt.should_receive( :send_alert ).with( @args ).once.and_return( "yeah" )
|
41
|
+
|
42
|
+
Rackamole::Alert::Twitt.deliver_alert( "blee", "duh", @args )
|
30
43
|
end
|
31
44
|
|
32
45
|
it "should twitt a feature alert correctly" do
|
@@ -36,7 +49,7 @@ describe Rackamole::Alert::Twitt do
|
|
36
49
|
# client.should_receive( :new ).exactly(1).with( 'fernand', 'blee' )
|
37
50
|
client.should_receive( :status ).once
|
38
51
|
|
39
|
-
@alert.send_alert( @args ).should == "[Feature] Test on Fred - Fernand\n/blee/fred"
|
52
|
+
@alert.send_alert( @args ).should == "[Feature] Test on Fred - Fernand\n/blee/fred - 12:00:00"
|
40
53
|
end
|
41
54
|
|
42
55
|
it "should twitt a perf alert correctly" do
|
@@ -48,7 +61,7 @@ describe Rackamole::Alert::Twitt do
|
|
48
61
|
@alert.should_receive( :twitt ).once.and_return( client )
|
49
62
|
client.should_receive( :status ).once
|
50
63
|
|
51
|
-
@alert.send_alert( @args ).should == "[Perf] Test on Fred - Fernand\n/blee/fred\n10.0 secs"
|
64
|
+
@alert.send_alert( @args ).should == "[Perf] Test on Fred - Fernand\n/blee/fred\n10.0 secs - 12:00:00"
|
52
65
|
end
|
53
66
|
|
54
67
|
it "should twitt a perf alert correctly" do
|
@@ -60,7 +73,7 @@ describe Rackamole::Alert::Twitt do
|
|
60
73
|
@alert.should_receive( :twitt ).once.and_return( client )
|
61
74
|
client.should_receive( :status ).once
|
62
75
|
|
63
|
-
@alert.send_alert( @args ).should == "[Fault] Test on Fred - Fernand\n/blee/fred\nOh snap!"
|
76
|
+
@alert.send_alert( @args ).should == "[Fault] Test on Fred - Fernand\n/blee/fred\nOh snap! - 12:00:00"
|
64
77
|
end
|
65
78
|
end
|
66
79
|
|
data/spec/rackamole/mole_spec.rb
CHANGED
@@ -4,8 +4,21 @@ describe Rack::Mole do
|
|
4
4
|
include Rack::Test::Methods
|
5
5
|
|
6
6
|
before :each do
|
7
|
-
@response
|
8
|
-
@
|
7
|
+
@response = [ 200, {"Content-Type" => "text/plain"}, ["success"] ]
|
8
|
+
@test_store = TestStore.new
|
9
|
+
@test_env = {
|
10
|
+
'rack.session' => { :user_id => 100, :username => "fernand" },
|
11
|
+
'HTTP_X_FORWARDED_FOR' => '1.1.1.1',
|
12
|
+
'HTTP_USER_AGENT' => "Firefox"
|
13
|
+
}
|
14
|
+
@opts = {
|
15
|
+
:app_name => "Test App",
|
16
|
+
:environment => :test,
|
17
|
+
:excluded_paths => ['/should_bail'],
|
18
|
+
:perf_threshold => 0.1,
|
19
|
+
:user_key => :username,
|
20
|
+
:store => @test_store
|
21
|
+
}
|
9
22
|
end
|
10
23
|
|
11
24
|
class TestStore
|
@@ -32,58 +45,158 @@ describe Rack::Mole do
|
|
32
45
|
end
|
33
46
|
end
|
34
47
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
48
|
+
def slow_app( opts={} )
|
49
|
+
response = @response
|
50
|
+
@app ||= Rack::Builder.new do
|
51
|
+
use Rack::Lint
|
52
|
+
use Rack::Mole, opts
|
53
|
+
run lambda { |env| sleep(0.2); response }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# ---------------------------------------------------------------------------
|
58
|
+
describe "fault duplicate" do
|
59
|
+
before( :each ) do
|
60
|
+
error_app( @opts )
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should mole a fault issue correctly" do
|
64
|
+
begin
|
65
|
+
get "/", nil, @test_env
|
66
|
+
rescue
|
67
|
+
last_request.env['mole.stash'].should_not be_nil
|
68
|
+
fault = last_request.env['mole.stash'].send( :find_fault, "/", "./spec/rackamole/mole_spec.rb:44:in `error_app'" )
|
69
|
+
fault.should_not be_nil
|
70
|
+
fault.count.should == 1
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should trap a recuring fault on given path correctly" do
|
75
|
+
env = @test_env
|
76
|
+
2.times do |i|
|
77
|
+
begin
|
78
|
+
get "/", nil, env
|
79
|
+
rescue
|
80
|
+
last_request.env['mole.stash'].should_not be_nil
|
81
|
+
fault = last_request.env['mole.stash'].send( :find_fault, "/", "./spec/rackamole/mole_spec.rb:44:in `error_app'" )
|
82
|
+
fault.should_not be_nil
|
83
|
+
fault.count.should == i+1
|
84
|
+
env = last_request.env
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should trap a recuring fault on different path correctly" do
|
90
|
+
env = @test_env
|
91
|
+
2.times do |i|
|
92
|
+
begin
|
93
|
+
env['PATH_INFO'] = "/#{i}"
|
94
|
+
get "/#{i}", nil, env
|
95
|
+
rescue
|
96
|
+
last_request.env['mole.stash'].should_not be_nil
|
97
|
+
fault = last_request.env['mole.stash'].send( :find_fault, "/", "./spec/rackamole/mole_spec.rb:44:in `error_app'" )
|
98
|
+
fault.should_not be_nil
|
99
|
+
fault.count.should == i+1
|
100
|
+
env = last_request.env
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# ---------------------------------------------------------------------------
|
107
|
+
describe "performance duplicate" do
|
108
|
+
before( :each ) do
|
109
|
+
@test_store = TestStore.new
|
110
|
+
slow_app( @opts )
|
111
|
+
end
|
43
112
|
|
113
|
+
it "should mole a perf issue correctly" do
|
114
|
+
get "/", nil, @test_env
|
115
|
+
last_request.env['mole.stash'].should_not be_nil
|
116
|
+
perf = last_request.env['mole.stash'].send( :find_perf, "/" )
|
117
|
+
perf.should_not be_nil
|
118
|
+
perf.count.should == 1
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should trap a recuring perf on given path correctly" do
|
122
|
+
env = @test_env
|
123
|
+
2.times do |i|
|
124
|
+
get "/", nil, env
|
125
|
+
perf = last_request.env['mole.stash'].send( :find_perf, "/" )
|
126
|
+
perf.should_not be_nil
|
127
|
+
perf.count.should == i+1
|
128
|
+
env = last_request.env
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should trap a recuring perf on different path correctly" do
|
133
|
+
env = @test_env
|
134
|
+
2.times do |i|
|
135
|
+
env['PATH_INFO'] = "/#{i}"
|
136
|
+
get "/#{i}", nil, env
|
137
|
+
last_request.env['mole.stash'].should_not be_nil
|
138
|
+
count = 0
|
139
|
+
while count <= i
|
140
|
+
perf = last_request.env['mole.stash'].send( :find_perf, "/#{count}" )
|
141
|
+
perf.should_not be_nil
|
142
|
+
perf.count.should == 1
|
143
|
+
count += 1
|
144
|
+
end
|
145
|
+
env = last_request.env
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
# ---------------------------------------------------------------------------
|
151
|
+
it "should mole a framwework exception correctly" do
|
152
|
+
error_app( @opts )
|
44
153
|
begin
|
45
154
|
get "/", nil, @test_env
|
46
155
|
rescue
|
47
|
-
@test_store.mole_result[:stack].should have(4).items
|
156
|
+
@test_store.mole_result[:stack].should have(4).items
|
157
|
+
last_request.env['mole.stash'].should_not be_nil
|
158
|
+
fault = last_request.env['mole.stash'].send( :find_fault, "/", "./spec/rackamole/mole_spec.rb:44:in `error_app'" )
|
159
|
+
fault.should_not be_nil
|
160
|
+
fault.count.should == 1
|
48
161
|
end
|
49
162
|
end
|
50
163
|
|
164
|
+
# ---------------------------------------------------------------------------
|
51
165
|
describe 'moling a request' do
|
52
166
|
before :each do
|
53
|
-
@
|
54
|
-
app(
|
55
|
-
:app_name => "Test App",
|
56
|
-
:environment => :test,
|
57
|
-
:perf_threshold => 0.1,
|
58
|
-
:user_key => { :session_key => :user_id, :extractor => lambda{ |k| "Fernand (#{k})"} },
|
59
|
-
:store => @test_store )
|
167
|
+
app( @opts )
|
60
168
|
end
|
61
169
|
|
62
170
|
it "should set the mole meta correctly" do
|
63
171
|
get "/fred/blee", nil, @test_env
|
64
|
-
@test_store.mole_result[:app_name].should
|
65
|
-
@test_store.mole_result[:environment].should
|
66
|
-
@test_store.mole_result[:user_id].should
|
67
|
-
@test_store.mole_result[:user_name].should
|
68
|
-
@test_store.mole_result[:ip].should
|
69
|
-
@test_store.mole_result[:browser].should
|
70
|
-
@test_store.mole_result[:method].should
|
71
|
-
@test_store.mole_result[:url].should
|
72
|
-
@test_store.mole_result[:path].should
|
73
|
-
@test_store.mole_result[:type].should
|
74
|
-
@test_store.mole_result[:params].should
|
75
|
-
@test_store.mole_result[:session].should_not
|
76
|
-
@test_store.mole_result[:session].should
|
172
|
+
@test_store.mole_result[:app_name].should == "Test App"
|
173
|
+
@test_store.mole_result[:environment].should == :test
|
174
|
+
@test_store.mole_result[:user_id].should be_nil
|
175
|
+
@test_store.mole_result[:user_name].should == 'fernand'
|
176
|
+
@test_store.mole_result[:ip].should == '1.1.1.1'
|
177
|
+
@test_store.mole_result[:browser].should == 'Firefox'
|
178
|
+
@test_store.mole_result[:method].should == 'GET'
|
179
|
+
@test_store.mole_result[:url].should == 'http://example.org/fred/blee'
|
180
|
+
@test_store.mole_result[:path].should == '/fred/blee'
|
181
|
+
@test_store.mole_result[:type].should == Rackamole.feature
|
182
|
+
@test_store.mole_result[:params].should be_nil
|
183
|
+
@test_store.mole_result[:session].should_not be_nil
|
184
|
+
@test_store.mole_result[:session].keys.should have(2).items
|
77
185
|
end
|
78
186
|
|
79
187
|
it "mole an exception correctly" do
|
80
188
|
begin
|
81
189
|
raise 'Oh snap!'
|
82
190
|
rescue => boom
|
83
|
-
|
191
|
+
@test_env['mole.exception'] = boom
|
192
|
+
get "/crap/out", nil, @test_env
|
84
193
|
@test_store.mole_result[:type].should == Rackamole.fault
|
85
194
|
@test_store.mole_result[:stack].should have(4).items
|
86
|
-
@test_store.mole_result[:fault].should == 'Oh snap!'
|
195
|
+
@test_store.mole_result[:fault].should == 'Oh snap!'
|
196
|
+
last_request.env['mole.stash'].should_not be_nil
|
197
|
+
fault = last_request.env['mole.stash'].send( :find_fault, "/", "./spec/rackamole/mole_spec.rb:189" )
|
198
|
+
fault.should_not be_nil
|
199
|
+
fault.count.should == 1
|
87
200
|
end
|
88
201
|
end
|
89
202
|
|
@@ -91,26 +204,86 @@ describe Rack::Mole do
|
|
91
204
|
get "/", { :blee => 'duh' }, @test_env
|
92
205
|
@test_store.mole_result[:params].should == { :blee => "duh".to_json }
|
93
206
|
end
|
207
|
+
|
208
|
+
it "should not mole an exclusion" do
|
209
|
+
get '/should_bail', nil, @test_env
|
210
|
+
@test_store.mole_result.should be_nil
|
211
|
+
end
|
94
212
|
end
|
95
213
|
|
214
|
+
# ---------------------------------------------------------------------------
|
96
215
|
describe 'username in session' do
|
97
|
-
before :each do
|
98
|
-
@test_store = TestStore.new
|
99
|
-
app(
|
100
|
-
:app_name => "Test App",
|
101
|
-
:environment => :test,
|
102
|
-
:perf_threshold => 0.1,
|
103
|
-
:user_key => :user_name,
|
104
|
-
:store => @test_store )
|
105
|
-
end
|
106
|
-
|
107
216
|
it "should pickup the user name from the session correctly" do
|
108
|
-
|
217
|
+
app( @opts )
|
218
|
+
get "/", nil, @test_env
|
109
219
|
@test_store.mole_result[:user_id].should be_nil
|
110
|
-
@test_store.mole_result[:user_name].should == '
|
220
|
+
@test_store.mole_result[:user_name].should == 'fernand'
|
221
|
+
end
|
222
|
+
|
223
|
+
it "should extract a username correctly" do
|
224
|
+
@opts[:user_key] = { :session_key => :user_id, :extractor => lambda { |k| "Fernand #{k}" } }
|
225
|
+
app( @opts )
|
226
|
+
get "/", nil, @test_env
|
227
|
+
@test_store.mole_result[:user_id].should == 100
|
228
|
+
@test_store.mole_result[:user_name].should == 'Fernand 100'
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
describe "rails env" do
|
233
|
+
it "should find route info correctly" do
|
234
|
+
RAILS_ENV = true
|
235
|
+
ActionController::Routing::Routes.stub!( :recognize_path ).and_return( { :controller => 'fred', :action => 'blee' } )
|
236
|
+
rack = Rack::Mole.new( nil )
|
237
|
+
|
238
|
+
# routes.should_receive( 'recognize_path' ).with( 'fred', { :method => 'blee' } ).and_return( )
|
239
|
+
res = rack.send( :get_route, OpenStruct.new( :path => "/", :request_method => "GET") )
|
240
|
+
res.should_not be_nil
|
241
|
+
res[:controller].should == 'fred'
|
242
|
+
res[:action].should == 'blee'
|
111
243
|
end
|
112
244
|
end
|
113
245
|
|
246
|
+
# ---------------------------------------------------------------------------
|
247
|
+
describe 'sending alerts' do
|
248
|
+
it "should send out alerts on the first occurrance of a perf issue" do
|
249
|
+
Rackamole::Alert::Twitt.stub!( :deliver_alert )
|
250
|
+
Rackamole::Alert::Emole.stub!( :deliver_alert )
|
251
|
+
|
252
|
+
@opts[:twitter] = { :username => "fred", :password => "blee", :alert_on => [Rackamole.perf] }
|
253
|
+
@opts[:email] = { :from => "fred", :to => ["blee"], :alert_on => [Rackamole.perf] }
|
254
|
+
|
255
|
+
slow_app( @opts )
|
256
|
+
|
257
|
+
Rackamole::Alert::Emole.should_receive( :deliver_alert ).once
|
258
|
+
Rackamole::Alert::Twitt.should_receive( :deliver_alert ).once
|
259
|
+
|
260
|
+
get "/", nil, @test_env
|
261
|
+
end
|
262
|
+
|
263
|
+
it "should should not send several alerts on an occurance of the same issue" do
|
264
|
+
Rackamole::Alert::Twitt.stub!( :deliver_alert )
|
265
|
+
Rackamole::Alert::Emole.stub!( :deliver_alert )
|
266
|
+
|
267
|
+
@opts[:twitter] = { :username => "fred", :password => "blee", :alert_on => [Rackamole.perf] }
|
268
|
+
@opts[:email] = { :from => "fred", :to => ["blee"], :alert_on => [Rackamole.perf] }
|
269
|
+
|
270
|
+
slow_app( @opts )
|
271
|
+
|
272
|
+
env = @test_env
|
273
|
+
# First time ok
|
274
|
+
Rackamole::Alert::Emole.should_receive( :deliver_alert ).once
|
275
|
+
Rackamole::Alert::Twitt.should_receive( :deliver_alert ).once
|
276
|
+
get "/", nil, env
|
277
|
+
env = last_request.env
|
278
|
+
# Second time - no alerts
|
279
|
+
Rackamole::Alert::Emole.should_not_receive( :deliver_alert )
|
280
|
+
Rackamole::Alert::Twitt.should_not_receive( :deliver_alert )
|
281
|
+
get "/", nil, env
|
282
|
+
end
|
283
|
+
|
284
|
+
end
|
285
|
+
|
286
|
+
# ---------------------------------------------------------------------------
|
114
287
|
describe '#alertable?' do
|
115
288
|
before( :each ) do
|
116
289
|
@rack = Rack::Mole.new( nil,
|
@@ -121,7 +294,7 @@ describe Rack::Mole do
|
|
121
294
|
},
|
122
295
|
:email => {
|
123
296
|
:from => 'fred',
|
124
|
-
:to => 'blee',
|
297
|
+
:to => ['blee'],
|
125
298
|
:alert_on => [Rackamole.perf, Rackamole.fault, Rackamole.feature]
|
126
299
|
} )
|
127
300
|
end
|
@@ -143,6 +316,7 @@ describe Rack::Mole do
|
|
143
316
|
end
|
144
317
|
end
|
145
318
|
|
319
|
+
# ---------------------------------------------------------------------------
|
146
320
|
describe '#configured?' do
|
147
321
|
before( :each ) do
|
148
322
|
options = {
|
@@ -176,6 +350,7 @@ describe Rack::Mole do
|
|
176
350
|
end
|
177
351
|
end
|
178
352
|
|
353
|
+
# ---------------------------------------------------------------------------
|
179
354
|
describe '#id_browser' do
|
180
355
|
before :all do
|
181
356
|
@rack = Rack::Mole.new( nil )
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), %w[.. .. spec_helper])
|
2
|
+
require 'chronic'
|
3
|
+
|
4
|
+
describe Rackamole::Stash::Collector do
|
5
|
+
before( :each ) do
|
6
|
+
@now = Chronic.parse( "11/27/2009" )
|
7
|
+
@collector = Rackamole::Stash::Collector.new( "Fred", "test" )
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "#stash" do
|
11
|
+
it "should record fault information correctly" do
|
12
|
+
begin
|
13
|
+
raise "Oh snap!"
|
14
|
+
rescue => boom
|
15
|
+
@collector.stash_fault( "/", boom.backtrace.first, @now )
|
16
|
+
@collector.send( :faults ).size.should == 1
|
17
|
+
|
18
|
+
fault = @collector.send( :find_fault, "/", boom.backtrace.first )
|
19
|
+
fault.should_not be_nil
|
20
|
+
fault.send( :path ).should == "/"
|
21
|
+
fault.send( :stack ).should == "./spec/rackamole/stash/collector_spec.rb:13"
|
22
|
+
fault.send( :timestamp ).should == @now
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should record perf information correctly" do
|
27
|
+
@collector.stash_perf( "/", 10.0, @now )
|
28
|
+
@collector.send( :perfs ).size.should == 1
|
29
|
+
|
30
|
+
perf = @collector.send( :find_perf, "/" )
|
31
|
+
perf.should_not be_nil
|
32
|
+
perf.send( :path ).should == "/"
|
33
|
+
perf.send( :elapsed ).should == 10.0
|
34
|
+
perf.send( :timestamp ).should == @now
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "#expire" do
|
39
|
+
before( :all ) do
|
40
|
+
@now = Chronic.parse( "11/27/2009" )
|
41
|
+
@yesterday = Chronic.parse( "yesterday", :now => @now )
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should expire fault correctly" do
|
45
|
+
begin
|
46
|
+
raise "Oh snap!"
|
47
|
+
rescue => boom
|
48
|
+
@collector.stash_fault( "/", boom.backtrace.first, @yesterday )
|
49
|
+
@collector.send( :faults ).size.should == 1
|
50
|
+
@collector.expire_faults!
|
51
|
+
@collector.send( :faults ).size.should == 0
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should expire perf correctly" do
|
56
|
+
@collector.stash_perf( "/", 10, @yesterday )
|
57
|
+
@collector.send( :perfs ).size.should == 1
|
58
|
+
@collector.expire_perfs!
|
59
|
+
@collector.send( :perfs ).size.should == 0
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), %w[.. .. spec_helper])
|
2
|
+
require 'chronic'
|
3
|
+
|
4
|
+
describe Rackamole::Stash::Fault do
|
5
|
+
before( :all ) do
|
6
|
+
@now = Chronic.parse( "11/27/2009" )
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should record fault information correctly" do
|
10
|
+
begin
|
11
|
+
raise "Oh snap!"
|
12
|
+
rescue => boom
|
13
|
+
fault = Rackamole::Stash::Fault.new( "/", boom.backtrace.first, @now )
|
14
|
+
fault.send( :path ).should == "/"
|
15
|
+
fault.send( :stack ).should == "./spec/rackamole/stash/fault_spec.rb:11"
|
16
|
+
fault.send( :timestamp ).should == @now
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), %w[.. .. spec_helper])
|
2
|
+
require 'chronic'
|
3
|
+
|
4
|
+
describe Rackamole::Stash::Perf do
|
5
|
+
before( :all ) do
|
6
|
+
@now = Chronic.parse( "11/27/2009" )
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should record perf information correctly" do
|
10
|
+
perf = Rackamole::Stash::Perf.new( "/", 10.0, @now )
|
11
|
+
perf.send( :path ).should == "/"
|
12
|
+
perf.send( :elapsed ).should == 10.0
|
13
|
+
perf.send( :timestamp ).should == @now
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
File without changes
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rackamole
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Fernand Galiana
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-11-
|
12
|
+
date: 2009-11-28 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -42,6 +42,16 @@ dependencies:
|
|
42
42
|
- !ruby/object:Gem::Version
|
43
43
|
version: 0.17.1
|
44
44
|
version:
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: chronic
|
47
|
+
type: :runtime
|
48
|
+
version_requirement:
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.2.3
|
54
|
+
version:
|
45
55
|
- !ruby/object:Gem::Dependency
|
46
56
|
name: twitter4r
|
47
57
|
type: :runtime
|
@@ -106,10 +116,13 @@ files:
|
|
106
116
|
- lib/rackamole/alert/emole.rb
|
107
117
|
- lib/rackamole/alert/templates/rackamole/alert/emole/alert.erb
|
108
118
|
- lib/rackamole/alert/twitt.rb
|
109
|
-
- lib/rackamole/config.rb
|
110
119
|
- lib/rackamole/interceptor.rb
|
111
120
|
- lib/rackamole/logger.rb
|
112
121
|
- lib/rackamole/mole.rb
|
122
|
+
- lib/rackamole/stash/base.rb
|
123
|
+
- lib/rackamole/stash/collector.rb
|
124
|
+
- lib/rackamole/stash/fault.rb
|
125
|
+
- lib/rackamole/stash/perf.rb
|
113
126
|
- lib/rackamole/store.rb
|
114
127
|
- lib/rackamole/store/log.rb
|
115
128
|
- lib/rackamole/store/mongo_db.rb
|
@@ -164,10 +177,16 @@ files:
|
|
164
177
|
- samples/rails/moled/script/server
|
165
178
|
- samples/rails/moled/test/performance/browsing_test.rb
|
166
179
|
- samples/rails/moled/test/test_helper.rb
|
167
|
-
- samples/sinatra/blee.rb
|
168
180
|
- samples/sinatra/moled.rb
|
181
|
+
- samples/sinatra/public/.DS_Store
|
182
|
+
- samples/sinatra/public/images/mole_logo.png
|
183
|
+
- samples/sinatra/public/stylesheets/styles.css
|
184
|
+
- samples/sinatra/views/index.erb
|
185
|
+
- samples/sinatra/views/layout.erb
|
169
186
|
- samples/sinatra/views/normal.erb
|
170
187
|
- samples/sinatra/views/params.erb
|
188
|
+
- samples/sinatra/views/post.erb
|
189
|
+
- samples/sinatra/views/slow.erb
|
171
190
|
- spec/expected_results/mole_exception.log
|
172
191
|
- spec/expected_results/mole_feature.log
|
173
192
|
- spec/expected_results/mole_perf.log
|
@@ -176,6 +195,9 @@ files:
|
|
176
195
|
- spec/rackamole/interceptor_spec.rb
|
177
196
|
- spec/rackamole/logger_spec.rb
|
178
197
|
- spec/rackamole/mole_spec.rb
|
198
|
+
- spec/rackamole/stash/collector_spec.rb
|
199
|
+
- spec/rackamole/stash/fault_spec.rb
|
200
|
+
- spec/rackamole/stash/perf_spec.rb
|
179
201
|
- spec/rackamole/store/log_spec.rb
|
180
202
|
- spec/rackamole/store/mongo_db_spec.rb
|
181
203
|
- spec/rackamole_spec.rb
|
@@ -194,6 +216,7 @@ files:
|
|
194
216
|
- tasks/zentest.rake
|
195
217
|
- z_experiments/config.rb
|
196
218
|
- z_experiments/config_sample.rb
|
219
|
+
- z_experiments/configuration.rb
|
197
220
|
has_rdoc: true
|
198
221
|
homepage: http://www.rackamole.com
|
199
222
|
licenses: []
|