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 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