rackamole 0.0.1

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.
Files changed (89) hide show
  1. data/History.txt +4 -0
  2. data/README.txt +93 -0
  3. data/Rakefile +28 -0
  4. data/aaa.txt +36 -0
  5. data/bin/rackamole +8 -0
  6. data/images/mole_logo.png +0 -0
  7. data/images/mole_logo.psd +0 -0
  8. data/images/mole_logo_small.png +0 -0
  9. data/images/mole_logo_small.psd +0 -0
  10. data/lib/rackamole.rb +46 -0
  11. data/lib/rackamole/interceptor.rb +20 -0
  12. data/lib/rackamole/logger.rb +121 -0
  13. data/lib/rackamole/mole.rb +134 -0
  14. data/lib/rackamole/store/log.rb +55 -0
  15. data/lib/rackamole/store/mongo.rb +104 -0
  16. data/samples/rails/moled/README +243 -0
  17. data/samples/rails/moled/Rakefile +10 -0
  18. data/samples/rails/moled/app/controllers/application_controller.rb +13 -0
  19. data/samples/rails/moled/app/controllers/fred_controller.rb +4 -0
  20. data/samples/rails/moled/app/helpers/application_helper.rb +3 -0
  21. data/samples/rails/moled/app/views/fred/index.html.erb +1 -0
  22. data/samples/rails/moled/config/boot.rb +110 -0
  23. data/samples/rails/moled/config/database.yml +22 -0
  24. data/samples/rails/moled/config/environment.rb +45 -0
  25. data/samples/rails/moled/config/environments/development.rb +17 -0
  26. data/samples/rails/moled/config/environments/production.rb +28 -0
  27. data/samples/rails/moled/config/environments/test.rb +28 -0
  28. data/samples/rails/moled/config/initializers/backtrace_silencers.rb +7 -0
  29. data/samples/rails/moled/config/initializers/inflections.rb +10 -0
  30. data/samples/rails/moled/config/initializers/mime_types.rb +5 -0
  31. data/samples/rails/moled/config/initializers/new_rails_defaults.rb +19 -0
  32. data/samples/rails/moled/config/initializers/session_store.rb +15 -0
  33. data/samples/rails/moled/config/locales/en.yml +5 -0
  34. data/samples/rails/moled/config/routes.rb +43 -0
  35. data/samples/rails/moled/db/development.sqlite3 +0 -0
  36. data/samples/rails/moled/doc/README_FOR_APP +2 -0
  37. data/samples/rails/moled/log/development.log +30 -0
  38. data/samples/rails/moled/log/production.log +0 -0
  39. data/samples/rails/moled/log/server.log +0 -0
  40. data/samples/rails/moled/log/test.log +0 -0
  41. data/samples/rails/moled/public/404.html +30 -0
  42. data/samples/rails/moled/public/422.html +30 -0
  43. data/samples/rails/moled/public/500.html +30 -0
  44. data/samples/rails/moled/public/favicon.ico +0 -0
  45. data/samples/rails/moled/public/images/rails.png +0 -0
  46. data/samples/rails/moled/public/index.html +275 -0
  47. data/samples/rails/moled/public/javascripts/application.js +2 -0
  48. data/samples/rails/moled/public/javascripts/controls.js +963 -0
  49. data/samples/rails/moled/public/javascripts/dragdrop.js +973 -0
  50. data/samples/rails/moled/public/javascripts/effects.js +1128 -0
  51. data/samples/rails/moled/public/javascripts/prototype.js +4320 -0
  52. data/samples/rails/moled/public/robots.txt +5 -0
  53. data/samples/rails/moled/script/about +4 -0
  54. data/samples/rails/moled/script/console +3 -0
  55. data/samples/rails/moled/script/dbconsole +3 -0
  56. data/samples/rails/moled/script/destroy +3 -0
  57. data/samples/rails/moled/script/generate +3 -0
  58. data/samples/rails/moled/script/performance/benchmarker +3 -0
  59. data/samples/rails/moled/script/performance/profiler +3 -0
  60. data/samples/rails/moled/script/plugin +3 -0
  61. data/samples/rails/moled/script/runner +3 -0
  62. data/samples/rails/moled/script/server +3 -0
  63. data/samples/rails/moled/test/performance/browsing_test.rb +9 -0
  64. data/samples/rails/moled/test/test_helper.rb +38 -0
  65. data/samples/sinatra/moled.rb +20 -0
  66. data/spec/expected_results/mole_exception.log +17 -0
  67. data/spec/expected_results/mole_feature.log +15 -0
  68. data/spec/expected_results/mole_perf.log +16 -0
  69. data/spec/rackamole/interceptor_spec.rb +33 -0
  70. data/spec/rackamole/logger_spec.rb +55 -0
  71. data/spec/rackamole/mole_spec.rb +90 -0
  72. data/spec/rackamole/store/log_spec.rb +54 -0
  73. data/spec/rackamole/store/mongo_spec.rb +120 -0
  74. data/spec/rackamole_spec.rb +20 -0
  75. data/spec/spec_helper.rb +8 -0
  76. data/tasks/ann.rake +80 -0
  77. data/tasks/bones.rake +20 -0
  78. data/tasks/gem.rake +201 -0
  79. data/tasks/git.rake +40 -0
  80. data/tasks/notes.rake +27 -0
  81. data/tasks/post_load.rake +34 -0
  82. data/tasks/rdoc.rake +51 -0
  83. data/tasks/rubyforge.rake +55 -0
  84. data/tasks/setup.rb +292 -0
  85. data/tasks/spec.rake +54 -0
  86. data/tasks/svn.rake +47 -0
  87. data/tasks/test.rake +40 -0
  88. data/tasks/zentest.rake +36 -0
  89. metadata +198 -0
data/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ == 1.0.0 / 2009-11-11
2
+
3
+ * 1 major enhancement
4
+ * Birthday!
data/README.txt ADDED
@@ -0,0 +1,93 @@
1
+ == RackAMole
2
+ Your web application observer...
3
+
4
+ == DESCRIPTION:
5
+
6
+ The MOle is a rack application that monitors user interactions with your web site. We are not
7
+ talking about counting page hits here. The MOle tracks all the information available to capture
8
+ the essence of a user interaction with your application. Using the MOle, you are able to see
9
+ which feature is a hit or a bust. As an added bonus, the MOle also track performance and exceptions
10
+ that might have escaped your test suites or alpha env. To boot your managers will love you for it!
11
+
12
+ Whether you are releasing a new application or improving on an old one, it is always a good thing
13
+ to know if anyone is using your application and if they are, how they are using it.
14
+ What features are your users most fond of and which features find their way into the abyss?
15
+ You will be able to rapidly assess whether or not your application is a hit and if
16
+ your coolest features are thought as such by your users. You will be able to elegantly record user
17
+ interactions and leverage these findings for the next iteration of your application.
18
+
19
+ == PROJECT INFORMATION
20
+
21
+ * Developer: Fernand Galiana [liquidrail.com]
22
+ * Forum: http://groups.google.com/group/rackamole
23
+ * Git: git://github.com/derailed/rackamole.git
24
+
25
+ == FEATURES:
26
+
27
+ * Monitors Rails or Sinatra applications
28
+ * Captures the essence of the request as well as user information
29
+ * Tracks performance issues based on your latency threshold
30
+ * Tracks exceptions that might occurred during a request
31
+
32
+ == REQUIREMENTS:
33
+
34
+ * Logging
35
+ * Hitimes
36
+ * MongoDb
37
+
38
+ == INSTALL:
39
+
40
+ * sudo gem install rackamole
41
+
42
+ NOTE: The gem is hosted on gemcutter.com - please update your gem sources if not
43
+ already specified
44
+
45
+ == USAGE:
46
+
47
+ === Rails applications
48
+
49
+ Edit your environment.rb file and add the following lines:
50
+
51
+ require 'rackamole'
52
+ config.middleware.use Rack::Mole, { :app_name => "My Cool App", :user_key => :user_name }
53
+
54
+ This instructs the mole to start logging information to the console and look for the user name
55
+ in the session using the :user_name key. There are other options available, please take a look
56
+ at the docs for more information.
57
+
58
+ === Sinatra Applications
59
+
60
+ Add the following lines in the config section and smoke it...
61
+
62
+ require 'rackamole'
63
+ configure do
64
+ use Rack::Mole, { :app_name => "My Sinatra App", :user_key => :user_name }
65
+ end
66
+
67
+ This assumes that you have session enabled to identify a user if not the mole will log the user
68
+ as 'Unknown'
69
+
70
+ == LICENSE:
71
+
72
+ (The MIT License)
73
+
74
+ Copyright (c) 2008 FIXME (different license?)
75
+
76
+ Permission is hereby granted, free of charge, to any person obtaining
77
+ a copy of this software and associated documentation files (the
78
+ 'Software'), to deal in the Software without restriction, including
79
+ without limitation the rights to use, copy, modify, merge, publish,
80
+ distribute, sublicense, and/or sell copies of the Software, and to
81
+ permit persons to whom the Software is furnished to do so, subject to
82
+ the following conditions:
83
+
84
+ The above copyright notice and this permission notice shall be
85
+ included in all copies or substantial portions of the Software.
86
+
87
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
88
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
89
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
90
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
91
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
92
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
93
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,28 @@
1
+ begin
2
+ require 'bones'
3
+ Bones.setup
4
+ rescue LoadError
5
+ begin
6
+ load 'tasks/setup.rb'
7
+ rescue LoadError
8
+ raise RuntimeError, '### please install the "bones" gem ###'
9
+ end
10
+ end
11
+
12
+ ensure_in_path 'lib'
13
+ require 'rackamole'
14
+
15
+ task :default => 'spec:run'
16
+
17
+ PROJ.name = 'rackamole'
18
+ PROJ.authors = 'Fernand Galiana'
19
+ PROJ.email = 'fernand.galiana@gmail.com'
20
+ PROJ.url = 'http://rackamole.liquidrail.com'
21
+ PROJ.version = Rackamole::VERSION
22
+ PROJ.spec.opts << '--color'
23
+ PROJ.ruby_opts = %w[-W0]
24
+
25
+ # Dependencies
26
+ depend_on "logging" , ">= 1.2.2"
27
+ depend_on "hitimes" , ">= 1.0.3"
28
+ depend_on "mongodb-mongo", ">= 0.14.1"
data/aaa.txt ADDED
@@ -0,0 +1,36 @@
1
+ == Problem
2
+
3
+ All tests green, CC happy, Customers are creaming their pants reading their Cucumber scenarios. App is in production on bitch'n servers.
4
+ Top of the world right?
5
+
6
+ == Questions
7
+
8
+ Is the app being used ? How many customers hit it in the past week ? What are the most/least used features ? Why?
9
+ Are my cool ajax callbacks silently crapping out? Are there any perf issues ? ... ?
10
+
11
+ == Got Mole ? (http://github.com/derailed/rackamole)
12
+
13
+ The MOle is a rack component that traps your application requests and captures the associated context information.
14
+ By intercepting the request, this rack app can gather calling context, alert you of latency issues on certain operation and
15
+ also trap any exceptions that may have emerged in the request cycle. The MOle is currently able to either store this information
16
+ in your log files or in a mongo instance for later processing.
17
+
18
+ == Options
19
+
20
+ <tt>:app_name</tt> - The name of the application [Default: Moled App]
21
+ <tt>:environment</tt> - The environment for the application ie :environment => RAILS_ENV
22
+ <tt>:moleable</tt> - Enable/Disable the MOle [Default:true]
23
+ <tt>:store </tt> - The storage instance ie log file or database [Default:stdout]
24
+ <tt>:user_key</tt> - If session is enable, the session key for the user name or user_id. ie :user_key => :user_name
25
+
26
+ == Rails
27
+
28
+ require 'rackamole'
29
+ config.middleware.use Rack::Mole, { :app_name => "My Cool App", :user_key => :user_name }
30
+
31
+ == Sinatra
32
+
33
+ require 'rackamole'
34
+ configure do
35
+ use Rack::Mole, { :app_name => "My Sinatra App", :user_key => :user_name }
36
+ end
data/bin/rackamole ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.expand_path(
4
+ File.join(File.dirname(__FILE__), %w[.. lib rackamole]))
5
+
6
+ # Put your code here
7
+
8
+ # EOF
Binary file
Binary file
Binary file
Binary file
data/lib/rackamole.rb ADDED
@@ -0,0 +1,46 @@
1
+ module Rackamole
2
+
3
+ # :stopdoc:
4
+ VERSION = '0.0.1'
5
+ LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
6
+ PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
7
+ # :startdoc:
8
+
9
+ # Returns the version string for the library.
10
+ #
11
+ def self.version
12
+ VERSION
13
+ end
14
+
15
+ # Returns the library path for the module. If any arguments are given,
16
+ # they will be joined to the end of the libray path using
17
+ # <tt>File.join</tt>.
18
+ #
19
+ def self.libpath( *args )
20
+ args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
21
+ end
22
+
23
+ # Returns the lpath for the module. If any arguments are given,
24
+ # they will be joined to the end of the path using
25
+ # <tt>File.join</tt>.
26
+ #
27
+ def self.path( *args )
28
+ args.empty? ? PATH : ::File.join(PATH, args.flatten)
29
+ end
30
+
31
+ # Utility method used to require all files ending in .rb that lie in the
32
+ # directory below this file that has the same name as the filename passed
33
+ # in. Optionally, a specific _directory_ name can be passed in such that
34
+ # the _filename_ does not have to be equivalent to the directory.
35
+ #
36
+ def self.require_all_libs_relative_to( fname, dir = nil )
37
+ dir ||= ::File.basename(fname, '.*')
38
+ search_me = ::File.expand_path(
39
+ ::File.join(::File.dirname(fname), dir, '**', '*.rb'))
40
+
41
+ Dir.glob(search_me).sort.each {|rb| require rb}
42
+ end
43
+
44
+ end
45
+
46
+ Rackamole.require_all_libs_relative_to(__FILE__)
@@ -0,0 +1,20 @@
1
+ module Rackamole
2
+ module Interceptor
3
+
4
+ # In order for the mole to trap framework exception, you must include
5
+ # the interceptor in your application controller.
6
+ # ie include Wackamole::Interceptor
7
+ def self.included( base )
8
+ base.send( :alias_method_chain, :rescue_action_in_public, :mole )
9
+ end
10
+
11
+ private
12
+
13
+ # Instructs the mole to trap the framework exception
14
+ def rescue_action_in_public_with_mole( exception )
15
+ # Stuff the exception in the env for mole rack retrieval
16
+ request.env['mole.exception'] = exception
17
+ rescue_action_in_public_without_mole( exception )
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,121 @@
1
+ require 'logging'
2
+ require 'forwardable'
3
+
4
+ module Rackamole
5
+ class Logger
6
+ class ConfigurationError < StandardError ; end #:nodoc:
7
+
8
+ attr_reader :log # here for testing, don't really use it.
9
+
10
+ extend Forwardable
11
+ def_delegators :@log, :debug, :warn, :info, :error, :fatal
12
+ def_delegators :@log, :level=, :level
13
+ def_delegators :@log, :debug?, :warn?, :info?, :error?, :fatal?
14
+ def_delegators :@log, :add, :clear_appenders
15
+
16
+ # there are more options here than are typically utilized for the
17
+ # logger, they are made available if someone wants to utilize
18
+ # them directly.
19
+ #
20
+ def self.default_options #:nodoc:
21
+ @default_options ||= {
22
+
23
+ # log event layout pattern
24
+ # YYYY-MM-DDTHH:MM:SS 12345 LEVEL LoggerName : The Log message
25
+ #
26
+ :layout_pattern => '%d %5p %5l %c : %m\n'.freeze ,
27
+ :logger_name => 'Mole' ,
28
+ :additive => true ,
29
+
30
+ # log file configuration options
31
+ # age -> how often to rotate the logs if a file is used
32
+ # keep_count -> how many of the log files to keep
33
+ :log_level => :info ,
34
+ :log_file => $stdout ,
35
+ :log_file_age => 'daily'.freeze ,
36
+ :log_file_keep_count => 7 ,
37
+
38
+ # email logging options
39
+ # buffsize -> number of log events used as a threshold to send an
40
+ # email. If that is not reached before the program
41
+ # exists then the at_exit handler for logging will flush
42
+ # the log to smtp.
43
+ :email_alerts_to => nil ,
44
+ :email_alert_level => :error ,
45
+ :email_alert_server => nil ,
46
+ :email_alert_buffsize => 200 ,
47
+ }
48
+ end
49
+
50
+ # create a new logger
51
+ #
52
+ def initialize( opts = {} )
53
+ @options = ::Rackamole::Logger.default_options.merge(opts)
54
+ @log = ::Logging::Logger[@options[:logger_name]]
55
+ @layout = ::Logging::Layouts::Pattern.new( { :pattern => @options[:layout_pattern] } )
56
+
57
+ # add appenders explicitly, since this logger may already be defined and
58
+ # already have loggers
59
+ @appenders = []
60
+ @appenders << log_file_appender if @options[:log_file]
61
+ @appenders << email_appender if @options[:email_alerts_to]
62
+
63
+ @log.appenders = @appenders
64
+ @log.level = @options[:log_level]
65
+ @log.additive = @options[:additive]
66
+ end
67
+
68
+ # File appender, this is either an IO appender or a RollingFile appender
69
+ # depending on if an IO object or a String is passed in.
70
+ #
71
+ # a configuration error is raised in any other circumstance
72
+ def log_file_appender #:nodoc:
73
+ appender_name = "#{@log.name}-log_file_appender"
74
+ if String === @options[:log_file] then
75
+ ::Logging::Appenders::RollingFile.new( appender_name,
76
+ { :layout => @layout,
77
+ :filename => @options[:log_file],
78
+ :age => @options[:log_file_age],
79
+ :keep => @options[:log_file_keep_count],
80
+ :safe => true # make sure log files are rolled using lockfile
81
+ })
82
+ elsif @options[:log_file].respond_to?(:print) then
83
+ ::Logging::Appenders::IO.new( appender_name, @options[:log_file], :layout => @layout )
84
+ else
85
+ raise ConfigurationError, "Invalid :log_file option [#{@options[:log_file].inspect}]"
86
+ end
87
+ end
88
+
89
+ # an email appender that uses :email_alerts_to option to send emails to.
90
+ # :email_alerts_to can either be a singe email address as a string or an
91
+ # Array of email addresses. Any other option for :email_alerts_to is
92
+ # invalid and raises an error.
93
+ #
94
+ def email_appender #:nodoc:
95
+ email_alerts_to = [ @options[:email_alerts_to] ].flatten.reject { |x| x == nil }
96
+ raise ConfigurationError, "Invalid :email_alerts_to option [#{@options[:email_alerts_to].inspect}]" unless email_alerts_to.size > 0
97
+ ::Logging::Appenders::Email.new("#{@log.name}-email_appender",
98
+ {
99
+ :level => @options[:email_alert_level],
100
+ :layout => @layout,
101
+ :from => "#{@log.name}",
102
+ :to => "#{email_alerts_to.join(', ')}",
103
+ :subject => "Logging Alert from #{@log.name} on #{ENV['HOSTNAME']}",
104
+ :server => @options[:email_alert_server],
105
+ :buffsize => @options[:email_alert_buffsize], # lines
106
+ })
107
+ end
108
+
109
+ # create a new logger thi logger has no options when it is created although
110
+ # more can be added with the logger instance that is returned. The
111
+ # appenders of the current instance of Logger will be set on the new
112
+ # logger and the options of the current logger will be applied
113
+ def for( arg ) #:nodoc:
114
+ new_logger = ::Logging::Logger[arg]
115
+ new_logger.level = @options[:level]
116
+ new_logger.additive = @options[:additive]
117
+ new_logger.appenders = @appenders
118
+ return new_logger
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,134 @@
1
+ require 'hitimes'
2
+ require 'mongo/util/ordered_hash'
3
+ require 'json'
4
+
5
+ module Rack
6
+ class Mole
7
+
8
+ # Initialize The Mole with the possible options
9
+ # <tt>:app_name</tt> - The name of the application [Default: Moled App]
10
+ # <tt>:environment</tt> - The environment for the application ie :environment => RAILS_ENV
11
+ # <tt>:perf_threshold</tt> - Any request taking longer than this value will get moled [Default: 10]
12
+ # <tt>:moleable</tt> - Enable/Disable the MOle [Default:true]
13
+ # <tt>:store</tt> - The storage instance ie log file or mongodb [Default:stdout]
14
+ # <tt>:user_key</tt> - If session is enable, the session key for the user name or user_id. ie :user_key => :user_name
15
+ def initialize( app, opts={} )
16
+ @app = app
17
+ init_options( opts )
18
+ end
19
+
20
+ def call( env )
21
+ # Bail if application is not moleable
22
+ return @app.call( env ) unless moleable?
23
+
24
+ response = nil
25
+ elapsed = Hitimes::Interval.measure do
26
+ response = @app.call( env )
27
+ end
28
+ @store.mole( mole_info( env, elapsed ) )
29
+ response
30
+ end
31
+
32
+ # ===========================================================================
33
+ private
34
+
35
+ # Load up configuration options
36
+ 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]
44
+ end
45
+
46
+ # Mole default options
47
+ def default_options
48
+ {
49
+ :app_name => "Moled App",
50
+ :moleable => true,
51
+ :perf_threshold => 10,
52
+ :store => Rackamole::Store::Log.new
53
+ }
54
+ end
55
+
56
+ # Extract interesting information from the request
57
+ def mole_info( env, elapsed )
58
+ request = Rack::Request.new( env )
59
+ session = env['rack.session']
60
+ route = get_route( request )
61
+ info = OrderedHash.new
62
+ ip, browser = identify( env )
63
+ user_id = nil
64
+ user_name = nil
65
+
66
+ if session and @user_key
67
+ if @user_key.instance_of? Symbol
68
+ user_name = session[@user_key]
69
+ elsif @user_key.instance_of? Hash
70
+ user_id = session[ @user_key[:session_key] ]
71
+ if @user_key[:extractor]
72
+ user_name = @user_key[:extractor].call( user_id )
73
+ end
74
+ end
75
+ end
76
+
77
+ info[:app_name] = @app_name
78
+ info[:environment] = @environment if @environment
79
+ info[:user_id] = user_id if user_id
80
+ info[:user_name] = user_name || "Unknown"
81
+ info[:ip] = ip
82
+ info[:browser] = browser
83
+ info[:request_time] = elapsed if elapsed
84
+ info[:perf_issue] = (elapsed and elapsed > @perf_threshold)
85
+ info[:url] = request.url
86
+ info[:method] = env['REQUEST_METHOD']
87
+ info[:path] = request.path
88
+ info[:route_info] = route if route
89
+
90
+ # Dump request params
91
+ unless request.params.empty?
92
+ info[:params] = OrderedHash.new
93
+ request.params.keys.sort.each { |k| info[:params][k.to_sym] = request.params[k].to_json }
94
+ end
95
+
96
+ # Dump session var
97
+ if session and !session.empty?
98
+ info[:session] = OrderedHash.new
99
+ session.keys.sort{ |a,b| a.to_s <=> b.to_s }.each { |k| info[:session][k.to_sym] = session[k].to_json }
100
+ end
101
+
102
+ # Check if an exception was raised. If so consume it and clear state
103
+ exception = env['mole.exception']
104
+ if exception
105
+ info[:ruby_version] = %x[ruby -v]
106
+ info[:stack] = trim_stack( exception )
107
+ env['mole.exception'] = nil
108
+ end
109
+
110
+ info
111
+ end
112
+
113
+ # Trim stack trace
114
+ def trim_stack( boom )
115
+ boom.backtrace[0...4]
116
+ end
117
+
118
+ # Identify request ie ip and browser configuration
119
+ def identify( request_env )
120
+ return request_env['HTTP_X_FORWARDED_FOR'] || request_env['REMOTE_ADDR'], request_env['HTTP_USER_AGENT']
121
+ end
122
+
123
+ # Checks if this application is moleable
124
+ def moleable?
125
+ @moleable
126
+ end
127
+
128
+ # Fetch route info if any...
129
+ def get_route( request )
130
+ return nil unless defined?( RAILS_ENV )
131
+ ::ActionController::Routing::Routes.recognize_path( request.path, {:method => request.request_method } )
132
+ end
133
+ end
134
+ end