rackamole 0.0.1 → 0.0.2

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