rackamole 0.0.9 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
- # depend_on "darkfish-rdoc", ">= 1.1.5"
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
- twitt.status( :post, truncate( twitt_msg ) ) if twitt_msg
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}"
@@ -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 = 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
- attrs = mole_info( env, elapsed, status, headers, body )
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
- # send email alert ?
119
- if alertable?( :email, attrs[:type] )
120
- Rackamole::Alert::Emole.deliver_alert( options[:email][:from], options[:email][:to], attrs )
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
- # send twitter alert ?
124
- if alertable?( :twitter, attrs[:type] )
125
- twitt.send_alert( attrs )
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
- # def dump( env, level=0 )
275
- # env.keys.sort{ |a,b| a.to_s <=> b.to_s }.each do |k|
276
- # value = env[k]
277
- # if value.respond_to?(:each_pair)
278
- # puts "%s %-#{40-level}s" % [' '*level,k]
279
- # dump( env[k], level+1 )
280
- # elsif value.instance_of?(::ActionController::Request) or value.instance_of?(::ActionController::Response)
281
- # puts "%s %-#{40-level}s %s" % [ ' '*level, k, value.class ]
282
- # else
283
- # puts "%s %-#{40-level}s %s" % [ ' '*level, k, value.inspect ]
284
- # end
285
- # end
286
- # end
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
@@ -0,0 +1,10 @@
1
+ module Rackamole::Stash
2
+ class Fault < Rackamole::Stash::Base
3
+ attr_reader :stack
4
+
5
+ def initialize( path, stack, timestamp )
6
+ super( path, timestamp )
7
+ @stack = stack
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ module Rackamole::Stash
2
+ class Perf < Rackamole::Stash::Base
3
+ attr_reader :elapsed
4
+
5
+ def initialize( path, elapsed, timestamp )
6
+ super( path, timestamp )
7
+ @elapsed = elapsed
8
+ end
9
+ end
10
+ 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
- id = features.save( row )
103
- features.find_one( id )
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( feature, args )
110
- now = Time.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 ) => feature['_id'].to_s,
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
@@ -1,7 +1,7 @@
1
1
  module Rackamole
2
2
 
3
3
  # :stopdoc:
4
- VERSION = '0.0.9'
4
+ VERSION = '0.1.0'
5
5
  LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
6
6
  PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
7
7
  # :startdoc:
@@ -1,5 +1,6 @@
1
1
  class FredController < ApplicationController
2
2
  def index
3
+ sleep( 1 )
3
4
  session[:fred] = 'hello'
4
5
  end
5
6
 
@@ -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, { :app_name => "My Cool App", :user_key => :user_name }
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]
@@ -2,34 +2,56 @@ require 'rubygems'
2
2
  require 'sinatra'
3
3
  require 'rackamole'
4
4
 
5
- configure do
6
- set :sessions, true
7
- set :environment, :development
8
- use Rack::Reloader
9
- use Rack::Mole, { :app_name => "My Sinatra App", :user_key => :user_name }
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 = "Snap!!"
18
- session[:fred] = "duh me"
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 = params[:id]
24
- session[:fred] = "duh me"
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 Shit!!"
51
+ raise "Oh Snap!"
30
52
  end
31
53
 
32
54
  get '/slow' do
33
- sleep 10
34
- '<h1> I am the slow one...</h1>'
55
+ sleep 0.2
56
+ erb :slow
35
57
  end
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 -- <%=@blee%></h1>
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] = Rackamole.feature
26
- @args[:app_name] = 'Test'
27
- @args[:host] = 'Fred'
28
- @args[:user_name] = 'Fernand'
29
- @args[:path] = '/blee/fred'
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
 
@@ -4,8 +4,21 @@ describe Rack::Mole do
4
4
  include Rack::Test::Methods
5
5
 
6
6
  before :each do
7
- @response = [ 200, {"Content-Type" => "text/plain"}, ["success"] ]
8
- @test_env = { 'rack.session' => { :user_id => 100 }, 'HTTP_X_FORWARDED_FOR' => '1.1.1.1', 'HTTP_USER_AGENT' => "Firefox" }
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
- it "should mole a framwework exception correctly" do
36
- @test_store = TestStore.new
37
- error_app(
38
- :app_name => "Test App",
39
- :environment => :test,
40
- :perf_threshold => 0.1,
41
- :user_key => { :session_key => :user_id, :extractor => lambda{ |k| "Test user #{k}"} },
42
- :store => @test_store )
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
- @test_store = TestStore.new
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 == "Test App"
65
- @test_store.mole_result[:environment].should == :test
66
- @test_store.mole_result[:user_id].should == 100
67
- @test_store.mole_result[:user_name].should == 'Fernand (100)'
68
- @test_store.mole_result[:ip].should == '1.1.1.1'
69
- @test_store.mole_result[:browser].should == 'Firefox'
70
- @test_store.mole_result[:method].should == 'GET'
71
- @test_store.mole_result[:url].should == 'http://example.org/fred/blee'
72
- @test_store.mole_result[:path].should == '/fred/blee'
73
- @test_store.mole_result[:type].should == Rackamole.feature
74
- @test_store.mole_result[:params].should be_nil
75
- @test_store.mole_result[:session].should_not be_nil
76
- @test_store.mole_result[:session].should == { :user_id => '100' }
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
- get "/crap/out", nil, @test_env.merge( { 'mole.exception' => boom } )
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
- get "/", nil, @test_env.merge( { 'rack.session' => { :user_name => "Fernand" } } )
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 == 'Fernand'
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
+
@@ -30,6 +30,7 @@ describe Rackamole::Store::MongoDb do
30
30
  @args[:method] = 'GET'
31
31
  @args[:params] = { :blee => "duh".to_json }
32
32
  @args[:session] = { :fred => 10.to_json }
33
+ @args[:created_at] = Time.now.utc
33
34
  end
34
35
 
35
36
  it "should mole a context based feature correctly" do
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.9
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-25 00:00:00 -07:00
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: []
@@ -1,7 +0,0 @@
1
- require 'rubygems'
2
- require 'sinatra'
3
- require 'forwardable'
4
-
5
- get '/' do
6
- 'Hello world!'
7
- end