rackamole 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.txt CHANGED
@@ -18,7 +18,10 @@ interactions and leverage these findings for the next iteration of your applicat
18
18
 
19
19
  == PROJECT INFORMATION
20
20
 
21
- * Developer: Fernand Galiana [liquidrail.com]
21
+ * Developer: Fernand Galiana
22
+ * Blog: liquidrail.com
23
+ * Site: rackamole.com
24
+ * Twitter: @rackamole
22
25
  * Forum: http://groups.google.com/group/rackamole
23
26
  * Git: git://github.com/derailed/rackamole.git
24
27
 
@@ -55,6 +58,14 @@ interactions and leverage these findings for the next iteration of your applicat
55
58
  in the session using the :user_name key. There are other options available, please take a look
56
59
  at the docs for more information.
57
60
 
61
+ Given Rails exception handling logic, you can also edit your application_controller.rb file and
62
+ include the mole interceptor to trap exceptions in production environment
63
+
64
+ class ApplicationController
65
+ include Rackamole::Interceptor
66
+
67
+ This will instruct the mole to trap the raised exception from your rails stack.
68
+
58
69
  === Sinatra Applications
59
70
 
60
71
  Add the following lines in the config section and smoke it...
data/lib/rackamole.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  module Rackamole
2
2
 
3
3
  # :stopdoc:
4
- VERSION = '0.0.1'
4
+ VERSION = '0.0.2'
5
5
  LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
6
6
  PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
7
7
  # :startdoc:
@@ -6,9 +6,17 @@ module Rackamole
6
6
  # ie include Wackamole::Interceptor
7
7
  def self.included( base )
8
8
  base.send( :alias_method_chain, :rescue_action_in_public, :mole )
9
+ base.send( :alias_method_chain, :rescue_action_locally, :mole )
9
10
  end
10
11
 
11
12
  private
13
+
14
+ # Instructs the mole to trap the framework exception
15
+ def rescue_action_locally_with_mole( exception )
16
+ # Stuff the exception in the env for mole rack retrieval
17
+ request.env['mole.exception'] = exception
18
+ rescue_action_locally_without_mole( exception )
19
+ end
12
20
 
13
21
  # Instructs the mole to trap the framework exception
14
22
  def rescue_action_in_public_with_mole( exception )
@@ -17,16 +17,22 @@ module Rack
17
17
  init_options( opts )
18
18
  end
19
19
 
20
- def call( env )
20
+ def call( env )
21
21
  # Bail if application is not moleable
22
22
  return @app.call( env ) unless moleable?
23
-
24
- response = nil
23
+
24
+ status, headers, body = nil
25
25
  elapsed = Hitimes::Interval.measure do
26
- response = @app.call( env )
26
+ begin
27
+ status, headers, body = @app.call( env )
28
+ rescue => boom
29
+ env['mole.exception'] = boom
30
+ @store.mole( mole_info( env, elapsed, status, headers, body ) )
31
+ raise boom
32
+ end
27
33
  end
28
- @store.mole( mole_info( env, elapsed ) )
29
- response
34
+ @store.mole( mole_info( env, elapsed, status, headers, body ) )
35
+ return status, headers, body
30
36
  end
31
37
 
32
38
  # ===========================================================================
@@ -34,31 +40,45 @@ module Rack
34
40
 
35
41
  # Load up configuration options
36
42
  def init_options( opts )
37
- options = default_options.merge( opts )
38
- @environment = options[:environment]
39
- @perf_threshold = options[:perf_threshold]
40
- @moleable = options[:moleable]
41
- @app_name = options[:app_name]
42
- @user_key = options[:user_key]
43
- @store = options[:store]
43
+ options = default_options.merge( opts )
44
+ @environment = options[:environment]
45
+ @perf_threshold = options[:perf_threshold]
46
+ @moleable = options[:moleable]
47
+ @app_name = options[:app_name]
48
+ @user_key = options[:user_key]
49
+ @store = options[:store]
50
+ @excluded_paths = options[:excluded_paths]
44
51
  end
45
52
 
46
53
  # Mole default options
47
54
  def default_options
48
55
  {
49
- :app_name => "Moled App",
50
- :moleable => true,
51
- :perf_threshold => 10,
52
- :store => Rackamole::Store::Log.new
56
+ :app_name => "Moled App",
57
+ :excluded_paths => [/.?\.ico/, /.?\.png/],
58
+ :moleable => true,
59
+ :perf_threshold => 10,
60
+ :store => Rackamole::Store::Log.new
53
61
  }
54
62
  end
55
-
63
+
64
+ # Check if this request should be moled according to the exclude filters
65
+ def mole_request?( request )
66
+ @excluded_paths.each do |exclude_path|
67
+ return false if request.path.match( exclude_path )
68
+ end
69
+ true
70
+ end
71
+
56
72
  # Extract interesting information from the request
57
- def mole_info( env, elapsed )
58
- request = Rack::Request.new( env )
73
+ def mole_info( env, elapsed, status, headers, body )
74
+ request = Rack::Request.new( env )
75
+ info = OrderedHash.new
76
+
77
+ return info unless mole_request?( request )
78
+
59
79
  session = env['rack.session']
60
80
  route = get_route( request )
61
- info = OrderedHash.new
81
+
62
82
  ip, browser = identify( env )
63
83
  user_id = nil
64
84
  user_name = nil
@@ -105,9 +125,11 @@ module Rack
105
125
  info[:ruby_version] = %x[ruby -v]
106
126
  info[:stack] = trim_stack( exception )
107
127
  env['mole.exception'] = nil
108
- end
109
-
128
+ end
110
129
  info
130
+ rescue => boom
131
+ $stderr.puts "!! MOLE RECORDING CRAPPED OUT !! -- #{boom}"
132
+ boom.backtrace.each { |l| $stderr.puts l }
111
133
  end
112
134
 
113
135
  # Trim stack trace
@@ -128,7 +150,7 @@ module Rack
128
150
  # Fetch route info if any...
129
151
  def get_route( request )
130
152
  return nil unless defined?( RAILS_ENV )
131
- ::ActionController::Routing::Routes.recognize_path( request.path, {:method => request.request_method } )
153
+ ::ActionController::Routing::Routes.recognize_path( request.path, {:method => request.request_method.downcase.to_sym } )
132
154
  end
133
155
  end
134
156
  end
@@ -9,6 +9,8 @@ module Rackamole
9
9
 
10
10
  # Dump mole info to logger
11
11
  def mole( args )
12
+ return if args.empty?
13
+
12
14
  if args[:stack]
13
15
  display_head "MOLED EXCEPTION"
14
16
  elsif args[:performance]
@@ -5,12 +5,15 @@ include Mongo
5
5
  # TODO !! Need to deal with auth
6
6
  module Rackamole
7
7
  module Store
8
- # Mongo adapter. Stores mole info in a mongo database
8
+ # Mongo adapter. Stores mole info in a mongo database.
9
+ # Two collections are available namely features and logs. Logs references
10
+ # the features collection.
9
11
  class Mongo
10
12
 
11
13
  attr_reader :connection
12
14
 
13
- def initialize( opts )
15
+ def initialize( options )
16
+ opts = default_options.merge( options )
14
17
  @connection = Connection.new( opts[:hostname], opts[:port] ).db( opts[:database] )
15
18
  end
16
19
 
@@ -22,6 +25,8 @@ module Rackamole
22
25
 
23
26
  # Dump mole info to logger
24
27
  def mole( args )
28
+ return if args.empty?
29
+
25
30
  feature = find_or_create_feature( args )
26
31
  log_feature( feature, args )
27
32
  rescue => mole_boom
@@ -29,17 +34,29 @@ module Rackamole
29
34
  $stderr.puts mole_boom.backtrace.join( "\n " )
30
35
  end
31
36
 
37
+ # Convenience to access mole features cltn
32
38
  def features
33
39
  @features ||= @connection['features']
34
40
  end
35
41
 
42
+ # Convenience to access mole log cltn
36
43
  def logs
37
44
  @logs ||= @connection['logs']
38
45
  end
39
46
 
40
47
  # =======================================================================
41
48
  private
42
-
49
+
50
+ # Set up mongo default options ie localhost host, default mongo port and
51
+ # the database being mole_mdb
52
+ def default_options
53
+ {
54
+ :host => 'localhost',
55
+ :port => 77926,
56
+ :database => 'mole_mdb'
57
+ }
58
+ end
59
+
43
60
  # retrieves a feature if exists or create a new one otherwise
44
61
  def find_or_create_feature( args )
45
62
  if args[:route_info]
@@ -88,7 +105,7 @@ module Rackamole
88
105
 
89
106
  row = {
90
107
  :type => type,
91
- :feature => ::DBRef.new( 'features', feature ),
108
+ :feature => ::DBRef.new( 'features', feature.instance_of?( ObjectID ) ? feature : feature['_id'] ),
92
109
  :created_at => Time.now,
93
110
  :updated_at => Time.now
94
111
  }
@@ -1,4 +1,6 @@
1
1
  class ApplicationController < ActionController::Base
2
+ include Rackamole::Interceptor
3
+
2
4
  helper :all # include all helpers, all the time
3
5
  protect_from_forgery # See ActionController::RequestForgeryProtection for details
4
6
 
@@ -10,4 +12,10 @@ class ApplicationController < ActionController::Base
10
12
  def setup
11
13
  session[:user_name] = "Fernand"
12
14
  end
15
+
16
+ protected
17
+
18
+ def local_request?
19
+ return false
20
+ end
13
21
  end
@@ -1,4 +1,13 @@
1
1
  class FredController < ApplicationController
2
2
  def index
3
+ session[:fred] = 'hello'
4
+ end
5
+
6
+ def edit
7
+ raise 'Oh snap!'
8
+ end
9
+
10
+ def show
11
+ @id = params[:id]
3
12
  end
4
13
  end
@@ -0,0 +1 @@
1
+ <h1>Hello <%=@id%></h1>
@@ -1,43 +1,6 @@
1
1
  ActionController::Routing::Routes.draw do |map|
2
- # The priority is based upon order of creation: first created -> highest priority.
2
+ map.resources :fred
3
3
 
4
- # Sample of regular route:
5
- # map.connect 'products/:id', :controller => 'catalog', :action => 'view'
6
- # Keep in mind you can assign values other than :controller and :action
7
-
8
- # Sample of named route:
9
- # map.purchase 'products/:id/purchase', :controller => 'catalog', :action => 'purchase'
10
- # This route can be invoked with purchase_url(:id => product.id)
11
-
12
- # Sample resource route (maps HTTP verbs to controller actions automatically):
13
- # map.resources :products
14
-
15
- # Sample resource route with options:
16
- # map.resources :products, :member => { :short => :get, :toggle => :post }, :collection => { :sold => :get }
17
-
18
- # Sample resource route with sub-resources:
19
- # map.resources :products, :has_many => [ :comments, :sales ], :has_one => :seller
20
-
21
- # Sample resource route with more complex sub-resources
22
- # map.resources :products do |products|
23
- # products.resources :comments
24
- # products.resources :sales, :collection => { :recent => :get }
25
- # end
26
-
27
- # Sample resource route within a namespace:
28
- # map.namespace :admin do |admin|
29
- # # Directs /admin/products/* to Admin::ProductsController (app/controllers/admin/products_controller.rb)
30
- # admin.resources :products
31
- # end
32
-
33
- # You can have the root of your site routed with map.root -- just remember to delete public/index.html.
34
- # map.root :controller => "welcome"
35
-
36
- # See how all your routes lay out with "rake routes"
37
-
38
- # Install the default routes as the lowest priority.
39
- # Note: These default routes make all actions in every controller accessible via GET requests. You should
40
- # consider removing the them or commenting them out if you're using named routes and resources.
41
4
  map.connect ':controller/:action/:id'
42
5
  map.connect ':controller/:action/:id.:format'
43
6
  end
File without changes
@@ -28,3 +28,53 @@ Completed in 113ms (View: 4, DB: 0) | 200 OK [http://localhost/fred]
28
28
  Processing FredController#index (for 127.0.0.1 at 2009-11-14 01:18:26) [GET]
29
29
  Rendering fred/index
30
30
  Completed in 6ms (View: 4, DB: 0) | 200 OK [http://localhost/fred]
31
+
32
+
33
+ Processing FredController#index (for 127.0.0.1 at 2009-11-15 11:36:33) [GET]
34
+ Rendering fred/index
35
+ Completed in 120ms (View: 4, DB: 0) | 200 OK [http://localhost/fred]
36
+
37
+
38
+ Processing FredController#show (for 127.0.0.1 at 2009-11-15 11:36:59) [GET]
39
+ Parameters: {"id"=>"list"}
40
+ Rendering fred/show
41
+ Completed in 4ms (View: 2, DB: 0) | 200 OK [http://localhost/fred/list]
42
+
43
+
44
+ Processing FredController#edit (for 127.0.0.1 at 2009-11-15 11:38:36) [GET]
45
+ Parameters: {"id"=>"10"}
46
+
47
+ RuntimeError (Oh snap!):
48
+ app/controllers/fred_controller.rb:7:in `edit'
49
+
50
+ Rendered rescues/_trace (27.9ms)
51
+ Rendered rescues/_request_and_response (1.2ms)
52
+ Rendering rescues/layout (internal_server_error)
53
+
54
+
55
+ Processing FredController#edit (for 127.0.0.1 at 2009-11-15 11:44:54) [GET]
56
+ Parameters: {"id"=>"10"}
57
+
58
+ RuntimeError (Oh snap!):
59
+ app/controllers/fred_controller.rb:7:in `edit'
60
+
61
+ Rendered rescues/_trace (29.1ms)
62
+ Rendered rescues/_request_and_response (1.2ms)
63
+ Rendering rescues/layout (internal_server_error)
64
+
65
+
66
+ Processing FredController#edit (for 127.0.0.1 at 2009-11-15 11:53:40) [GET]
67
+ Parameters: {"id"=>"10"}
68
+
69
+ RuntimeError (Oh snap!):
70
+ app/controllers/fred_controller.rb:7:in `edit'
71
+
72
+ Rendered rescues/_trace (28.4ms)
73
+ Rendered rescues/_request_and_response (1.3ms)
74
+ Rendering rescues/layout (internal_server_error)
75
+
76
+
77
+ Processing FredController#show (for 127.0.0.1 at 2009-11-15 11:54:08) [GET]
78
+ Parameters: {"id"=>"10"}
79
+ Rendering fred/show
80
+ Completed in 7ms (View: 6, DB: 0) | 200 OK [http://localhost/fred/10]
@@ -0,0 +1,36 @@
1
+
2
+
3
+ Processing FredController#edit (for 127.0.0.1 at 2009-11-15 11:39:29) [GET]
4
+ Parameters: {"id"=>"10"}
5
+
6
+ RuntimeError (Oh snap!):
7
+ app/controllers/fred_controller.rb:7:in `edit'
8
+
9
+ Rendering rescues/layout (internal_server_error)
10
+
11
+
12
+ Processing FredController#edit (for 127.0.0.1 at 2009-11-15 11:40:41) [GET]
13
+ Parameters: {"id"=>"10"}
14
+
15
+ RuntimeError (Oh snap!):
16
+ app/controllers/fred_controller.rb:7:in `edit'
17
+
18
+ Rendering /Users/fgaliana/work/git/rackamole/samples/rails/moled/public/500.html (500 Internal Server Error)
19
+
20
+
21
+ Processing FredController#edit (for 127.0.0.1 at 2009-11-15 11:41:39) [GET]
22
+ Parameters: {"id"=>"10"}
23
+
24
+ RuntimeError (Oh snap!):
25
+ app/controllers/fred_controller.rb:7:in `edit'
26
+
27
+ Rendering /Users/fgaliana/work/git/rackamole/samples/rails/moled/public/500.html (500 Internal Server Error)
28
+
29
+
30
+ Processing FredController#edit (for 127.0.0.1 at 2009-11-15 11:43:03) [GET]
31
+ Parameters: {"id"=>"10"}
32
+
33
+ RuntimeError (Oh snap!):
34
+ app/controllers/fred_controller.rb:7:in `edit'
35
+
36
+ Rendering /Users/fgaliana/work/git/rackamole/samples/rails/moled/public/500.html (500 Internal Server Error)
@@ -0,0 +1,7 @@
1
+ require 'rubygems'
2
+ require 'sinatra'
3
+ require 'forwardable'
4
+
5
+ get '/' do
6
+ 'Hello world!'
7
+ end
@@ -13,8 +13,23 @@ before do
13
13
  session[:user_name] = "Fernand"
14
14
  end
15
15
 
16
- get '/fred' do
17
- @blee = "No shit"
16
+ get '/normal' do
17
+ @blee = "Snap!!"
18
18
  session[:fred] = "duh me"
19
- "<h1>Hello World</h1>"
19
+ erb :normal
20
+ end
21
+
22
+ get '/params/:id' do
23
+ @blee = params[:id]
24
+ session[:fred] = "duh me"
25
+ erb :params
26
+ end
27
+
28
+ get '/error' do
29
+ raise "Oh Shit!!"
30
+ end
31
+
32
+ get '/slow' do
33
+ sleep 10
34
+ '<h1> I am the slow one...</h1>'
20
35
  end
@@ -0,0 +1 @@
1
+ <h1>Normal -- <%=@blee%></h1>
@@ -0,0 +1 @@
1
+ <h1>Params -- <%=@blee%></h1>
@@ -6,6 +6,9 @@ describe Rackamole::Interceptor do
6
6
  class Fred
7
7
  def rescue_action_in_public( exception )
8
8
  end
9
+
10
+ def rescue_action_locally( exception )
11
+ end
9
12
 
10
13
  def request
11
14
  @request ||= OpenStruct.new( :env => {} )
@@ -20,10 +23,19 @@ describe Rackamole::Interceptor do
20
23
  end
21
24
  end
22
25
 
23
- it "should include the correct methods" do
26
+ it "should include the correct methods" do
27
+ Fred.instance_methods.should be_include( 'rescue_action_locally_without_mole' )
28
+ Fred.private_instance_methods.should be_include( 'rescue_action_locally_with_mole' )
29
+
24
30
  Fred.instance_methods.should be_include( 'rescue_action_in_public_without_mole' )
25
31
  Fred.private_instance_methods.should be_include( 'rescue_action_in_public_with_mole' )
26
32
  end
33
+
34
+ it "should set the env correctly when a local exception is raised" do
35
+ fred = Fred.new
36
+ fred.send( :rescue_action_locally, "Fred" )
37
+ fred.request.env['mole.exception'].should == "Fred"
38
+ end
27
39
 
28
40
  it "should set the env correctly when an exception is raised" do
29
41
  fred = Fred.new
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.1
4
+ version: 0.0.2
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-14 00:00:00 -07:00
12
+ date: 2009-11-15 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -96,6 +96,7 @@ files:
96
96
  - samples/rails/moled/app/controllers/fred_controller.rb
97
97
  - samples/rails/moled/app/helpers/application_helper.rb
98
98
  - samples/rails/moled/app/views/fred/index.html.erb
99
+ - samples/rails/moled/app/views/fred/show.html.erb
99
100
  - samples/rails/moled/config/boot.rb
100
101
  - samples/rails/moled/config/database.yml
101
102
  - samples/rails/moled/config/environment.rb
@@ -110,6 +111,7 @@ files:
110
111
  - samples/rails/moled/config/locales/en.yml
111
112
  - samples/rails/moled/config/routes.rb
112
113
  - samples/rails/moled/db/development.sqlite3
114
+ - samples/rails/moled/db/production.sqlite3
113
115
  - samples/rails/moled/doc/README_FOR_APP
114
116
  - samples/rails/moled/log/development.log
115
117
  - samples/rails/moled/log/production.log
@@ -139,7 +141,10 @@ files:
139
141
  - samples/rails/moled/script/server
140
142
  - samples/rails/moled/test/performance/browsing_test.rb
141
143
  - samples/rails/moled/test/test_helper.rb
144
+ - samples/sinatra/blee.rb
142
145
  - samples/sinatra/moled.rb
146
+ - samples/sinatra/views/normal.erb
147
+ - samples/sinatra/views/params.erb
143
148
  - spec/expected_results/mole_exception.log
144
149
  - spec/expected_results/mole_feature.log
145
150
  - spec/expected_results/mole_perf.log