rackamole 0.0.6 → 0.0.7
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.rdoc +1 -1
- data/Rakefile +3 -1
- data/aa.txt +10 -0
- data/lib/rackamole.rb +6 -5
- data/lib/rackamole/alert/emole.rb +67 -0
- data/lib/rackamole/alert/templates/rackamole/alert/emole/alert.erb +9 -0
- data/lib/rackamole/alert/twitt.rb +73 -0
- data/lib/rackamole/interceptor.rb +7 -1
- data/lib/rackamole/logger.rb +5 -2
- data/lib/rackamole/mole.rb +116 -35
- data/lib/rackamole/store.rb +4 -0
- data/lib/rackamole/store/log.rb +55 -50
- data/lib/rackamole/store/mongo_db.rb +46 -26
- data/spec/expected_results/mole_exception.log +3 -2
- data/spec/expected_results/mole_feature.log +2 -2
- data/spec/expected_results/mole_perf.log +2 -3
- data/spec/rackamole/alert/emole_spec.rb +109 -0
- data/spec/rackamole/alert/twitt_spec.rb +68 -0
- data/spec/rackamole/mole_spec.rb +61 -9
- data/spec/rackamole/store/log_spec.rb +5 -3
- data/spec/rackamole/store/mongo_db_spec.rb +12 -8
- data/z_experiments/config.rb +38 -0
- metadata +31 -2
data/README.rdoc
CHANGED
@@ -82,7 +82,7 @@ interactions and leverage these findings for the next iteration of your applicat
|
|
82
82
|
|
83
83
|
(The MIT License)
|
84
84
|
|
85
|
-
Copyright (c)
|
85
|
+
Copyright (c) 2009
|
86
86
|
|
87
87
|
Permission is hereby granted, free of charge, to any person obtaining
|
88
88
|
a copy of this software and associated documentation files (the
|
data/Rakefile
CHANGED
@@ -28,4 +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 "darkfish-rdoc", ">= 1.1.5"
|
32
|
+
depend_on "twitter4r" , ">= 0.3.0"
|
33
|
+
depend_on "actionmailer" , ">= 2.1.0"
|
data/aa.txt
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
:twitt_if => [Rackamole.feature, Rackamole.fault, Rackamole.perf],
|
2
|
+
:twitter => { :username => 'moled', :password => 'fernand~1' },
|
3
|
+
|
4
|
+
require 'action_mailer'
|
5
|
+
ActionMailer::Base.delivery_method = :sendmail
|
6
|
+
ActionMailer::Base.raise_delivery_errors = true
|
7
|
+
|
8
|
+
:email => { :from => 'fernand@collectiveintellect.com', :to => ['fernand@collectiveintellect.com'] },
|
9
|
+
:email_if => [Rackamole.feature, Rackamole.fault],
|
10
|
+
|
data/lib/rackamole.rb
CHANGED
@@ -1,21 +1,24 @@
|
|
1
1
|
module Rackamole
|
2
2
|
|
3
3
|
# :stopdoc:
|
4
|
-
VERSION = '0.0.
|
4
|
+
VERSION = '0.0.7'
|
5
5
|
LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
|
6
6
|
PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
|
7
7
|
# :startdoc:
|
8
8
|
|
9
9
|
# Returns the version string for the library.
|
10
|
-
#
|
11
10
|
def self.version
|
12
11
|
VERSION
|
13
12
|
end
|
14
13
|
|
14
|
+
# Defines the default moled activity types
|
15
|
+
def self.feature() 0; end
|
16
|
+
def self.perf() 1; end
|
17
|
+
def self.fault() 2; end
|
18
|
+
|
15
19
|
# Returns the library path for the module. If any arguments are given,
|
16
20
|
# they will be joined to the end of the libray path using
|
17
21
|
# <tt>File.join</tt>.
|
18
|
-
#
|
19
22
|
def self.libpath( *args )
|
20
23
|
args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
|
21
24
|
end
|
@@ -23,7 +26,6 @@ module Rackamole
|
|
23
26
|
# Returns the lpath for the module. If any arguments are given,
|
24
27
|
# they will be joined to the end of the path using
|
25
28
|
# <tt>File.join</tt>.
|
26
|
-
#
|
27
29
|
def self.path( *args )
|
28
30
|
args.empty? ? PATH : ::File.join(PATH, args.flatten)
|
29
31
|
end
|
@@ -32,7 +34,6 @@ module Rackamole
|
|
32
34
|
# directory below this file that has the same name as the filename passed
|
33
35
|
# in. Optionally, a specific _directory_ name can be passed in such that
|
34
36
|
# the _filename_ does not have to be equivalent to the directory.
|
35
|
-
#
|
36
37
|
def self.require_all_libs_relative_to( fname, dir = nil )
|
37
38
|
dir ||= ::File.basename(fname, '.*')
|
38
39
|
search_me = ::File.expand_path(
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'action_mailer'
|
2
|
+
|
3
|
+
module Rackamole::Alert
|
4
|
+
class Emole < ActionMailer::Base
|
5
|
+
self.template_root = File.join( File.dirname(__FILE__), %w[templates] )
|
6
|
+
|
7
|
+
# Send an email notification for particular moled feature. An email will
|
8
|
+
# be sent based on the two configuration :emails and :mail_on defined on the
|
9
|
+
# Rack::Mole component. These specify the to and from addresses and the conditions
|
10
|
+
# that will trigger the email, currently :enabled and :features for the type of
|
11
|
+
# moled features to track via email. The notification will be sent via actionmailer,
|
12
|
+
# so you will need to make sure it is properly configured for your domain.
|
13
|
+
# NOTE: This is just a notification mechanism. All moled event will be either logged
|
14
|
+
# or persisted in the db regardless.
|
15
|
+
#
|
16
|
+
# === Parameters:
|
17
|
+
# from :: The from address address. Must be a valid domain.
|
18
|
+
# recipients :: An array of email addresses for recipients to be notified.
|
19
|
+
# args :: The gathered information from the mole.
|
20
|
+
#
|
21
|
+
def alert( from, recipients, args )
|
22
|
+
buff = []
|
23
|
+
|
24
|
+
dump( buff, args, 0 )
|
25
|
+
|
26
|
+
from from
|
27
|
+
recipients recipients
|
28
|
+
subject "[M()le] (#{alert_type( args )}#{request_time?( args )}) -#{args[:app_name]}@#{args[:host]}- for user #{args[:user_name]}"
|
29
|
+
body :args => args,
|
30
|
+
:dump => buff.join( "\n" )
|
31
|
+
end
|
32
|
+
|
33
|
+
# =========================================================================
|
34
|
+
private
|
35
|
+
|
36
|
+
# Dump request time if any...
|
37
|
+
def request_time?( args )
|
38
|
+
args[:type] == Rackamole.perf ? ":#{args[:request_time]}" : ''
|
39
|
+
end
|
40
|
+
|
41
|
+
# Identify the type of alert...
|
42
|
+
def alert_type( args )
|
43
|
+
case args[:type]
|
44
|
+
when Rackamole.feature : "Feature"
|
45
|
+
when Rackamole.perf : "Performance"
|
46
|
+
when Rackamole.fault : "Fault"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Dump args...
|
51
|
+
def dump( buff, env, level=0 )
|
52
|
+
env.each_pair do |k,value|
|
53
|
+
if value.respond_to?(:each_pair)
|
54
|
+
buff << "%s %-#{40-level}s" % [' '*level,k]
|
55
|
+
dump( buff, env[k], level+1 )
|
56
|
+
elsif value.instance_of?(Array)
|
57
|
+
buff << "%s %-#{40-level}s" % [' '*level,k]
|
58
|
+
value.each do |v|
|
59
|
+
buff << "%s %-#{40-(level+1)}s" % [' '*(level+1),v]
|
60
|
+
end
|
61
|
+
else
|
62
|
+
buff << "%s %-#{40-level}s %s" % [ ' '*level, k, value.inspect ]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'twitter'
|
2
|
+
|
3
|
+
module Rackamole::Alert
|
4
|
+
# Leverage twitter as a notification client. You can setup a private twitter account
|
5
|
+
# and have your moled app twitt exception/perf alerts...
|
6
|
+
class Twitt
|
7
|
+
|
8
|
+
# This class is used to send out moled twitter notification. This feature is enabled
|
9
|
+
# by setting both :twitter_auth and twitt_on options on the Rack::Mole. When a moled
|
10
|
+
# feature comes around it will be twitted on your configured account. This allow your
|
11
|
+
# app to twitt about it's status and issues. Currently there are no provisions to throttle
|
12
|
+
# the twitts, hence sending out twitt notifications of every moled features would not be
|
13
|
+
# a very good idea. Whereas sending twitts when your application bogs down or throws exception,
|
14
|
+
# might be more appropriate. Further work will take place to throttle these events...
|
15
|
+
# Creating a private twitter account and asking folks in your group to follow might be an
|
16
|
+
# alternative to email.
|
17
|
+
#
|
18
|
+
# NOTE: This is just an alert mechanism. All moled events will be either logged or persisted in the db
|
19
|
+
# regardless.
|
20
|
+
#
|
21
|
+
# === Params:
|
22
|
+
# username :: The name on the twitter account
|
23
|
+
# password :: The password of your twitter account
|
24
|
+
def initialize( username, password )
|
25
|
+
raise "You must specify your twitter account credentials" unless username or password
|
26
|
+
@username = username
|
27
|
+
@password = password
|
28
|
+
end
|
29
|
+
|
30
|
+
# Send out a twitt notification based of the watched features. A short message will be blasted to your twitter
|
31
|
+
# account based on information reported by the mole. The twitt will be automatically truncated
|
32
|
+
# to 140 chars.
|
33
|
+
#
|
34
|
+
# === Params:
|
35
|
+
# args :: The moled info for a given feature.
|
36
|
+
#
|
37
|
+
def send_alert( args )
|
38
|
+
twitt_msg = "#{args[:app_name]}:#{args[:host]}\n#{args[:user_name]} : #{display_feature(args)}"
|
39
|
+
twitt_msg = case args[:type]
|
40
|
+
when Rackamole.feature : "[Feature] -- #{twitt_msg}"
|
41
|
+
when Rackamole.perf : "[Perf] -- #{twitt_msg} : #{args[:request_time]} secs"
|
42
|
+
when Rackamole.fault : "[Fault] -- #{twitt_msg} : #{args[:fault]}"
|
43
|
+
else nil
|
44
|
+
end
|
45
|
+
twitt.status( :post, truncate( twitt_msg ) ) if twitt_msg
|
46
|
+
twitt_msg
|
47
|
+
rescue => boom
|
48
|
+
$stderr.puts "TWITT mole failed with #{boom}"
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
attr_reader :username, :password #:nodoc:
|
54
|
+
|
55
|
+
# Fetch twitter connection...
|
56
|
+
def twitt
|
57
|
+
@twitt ||= ::Twitter::Client.new( :login => username, :password => password )
|
58
|
+
end
|
59
|
+
|
60
|
+
# Display controller/action or path depending on frmk used...
|
61
|
+
def display_feature( args )
|
62
|
+
return args[:path] unless args[:route_info]
|
63
|
+
"#{args[:route_info][:controller]}##{args[:route_info][:action]}"
|
64
|
+
end
|
65
|
+
|
66
|
+
# Truncate for twitt max size
|
67
|
+
def truncate(text, length = 140, truncate_string = "...")
|
68
|
+
return "" if text.nil?
|
69
|
+
l = length - truncate_string.mb_chars.length
|
70
|
+
text.mb_chars.length > length ? (text.mb_chars[0...l] + truncate_string).to_s : text
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -1,9 +1,15 @@
|
|
1
1
|
module Rackamole
|
2
2
|
module Interceptor
|
3
3
|
|
4
|
+
# === For Rails only!
|
5
|
+
#
|
6
|
+
# Rails handles raised exception in a special way.
|
7
|
+
# Thus special care need to be taken to enable exception to bubble up
|
8
|
+
# to the mole.
|
9
|
+
#
|
4
10
|
# In order for the mole to trap framework exception, you must include
|
5
11
|
# the interceptor in your application controller.
|
6
|
-
# ie include
|
12
|
+
# ie include Rackamole::Interceptor
|
7
13
|
def self.included( base )
|
8
14
|
base.send( :alias_method_chain, :rescue_action_in_public, :mole )
|
9
15
|
base.send( :alias_method_chain, :rescue_action_locally, :mole )
|
data/lib/rackamole/logger.rb
CHANGED
@@ -5,7 +5,7 @@ module Rackamole
|
|
5
5
|
class Logger
|
6
6
|
class ConfigurationError < StandardError ; end #:nodoc:
|
7
7
|
|
8
|
-
attr_reader :log
|
8
|
+
attr_reader :log #:nodoc:
|
9
9
|
|
10
10
|
extend Forwardable
|
11
11
|
def_delegators :@log, :debug, :warn, :info, :error, :fatal
|
@@ -47,7 +47,10 @@ module Rackamole
|
|
47
47
|
}
|
48
48
|
end
|
49
49
|
|
50
|
-
#
|
50
|
+
# Creates a logger for mole usage by leveraging the most excellent logging gem.
|
51
|
+
# This provides for a semi persistent storage for mole information, typically set up
|
52
|
+
# for the console or a file. By default moled features will be sent out to the console.
|
53
|
+
# Alternatively you can store the moled info to a file.
|
51
54
|
#
|
52
55
|
def initialize( opts = {} )
|
53
56
|
@options = ::Rackamole::Logger.default_options.merge(opts)
|
data/lib/rackamole/mole.rb
CHANGED
@@ -2,21 +2,59 @@ require 'hitimes'
|
|
2
2
|
require 'json'
|
3
3
|
require 'mongo'
|
4
4
|
|
5
|
+
# BOZO !! - Need args validator or use dsl as the args are out of control...
|
5
6
|
module Rack
|
6
7
|
class Mole
|
7
8
|
|
8
|
-
# Initialize The Mole
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
9
|
+
# Initialize The Mole rack component. It is recommended that you specify at a minimum a user_key to track
|
10
|
+
# interactions on a per user basis. If you wish to use the mole for the same application in different
|
11
|
+
# environments you should set the environment attribute RAILS_ENV for example. The perf_threshold setting
|
12
|
+
# is also recommended to get performance notifications should your web app start sucking.
|
13
|
+
# By default your app will be moleable upon installation and you should see mole features spewing out in your
|
14
|
+
# logs. This is the default setting. Alternatively you can store mole information in a mongo database by
|
15
|
+
# specifying a different store option.
|
16
|
+
#
|
17
|
+
# === Options
|
18
|
+
#
|
19
|
+
# :app_name :: The name of the application (Default: Moled App)
|
20
|
+
# :environment :: The environment for the application ie :environment => RAILS_ENV
|
21
|
+
# :perf_threshold :: Any request taking longer than this value will get moled. Default: 10secs
|
22
|
+
# :moleable :: Enable/Disable the MOle (Default:true)
|
23
|
+
# :store :: The storage instance ie log file or mongodb [Default:stdout]
|
24
|
+
# :user_key :: If sessions are enable, this represents the session key for the user name or
|
25
|
+
# user_id.
|
26
|
+
# ==
|
27
|
+
# If the username resides in the session hash with key :user_name the you can use:
|
28
|
+
# :user_key => :user_name
|
29
|
+
# Or you can eval it on the fly - though this will be much slower and not recommended
|
30
|
+
# :user_key => { :session_key => :user_id, :extractor => lambda{ |id| User.find( id ).name} }
|
31
|
+
# ==
|
32
|
+
#
|
33
|
+
# :twitter_auth :: You can setup the MOle twit interesting events to a private (public if you indulge pain!) twitter account.
|
34
|
+
# Specified your twitter account information using a hash with :username and :password key
|
35
|
+
# :twitt_on :: You must configure your twitter auth and configuration using this hash. By default this option is disabled.
|
36
|
+
# ==
|
37
|
+
# :twitt_on => { :enabled => false, :features => [Rackamole.perf, Rackamole.fault] }
|
38
|
+
# ==
|
39
|
+
# ==== BOZO! currently there is not support for throttling or monitoring these alerts.
|
40
|
+
# ==
|
41
|
+
# :emails :: The mole can be configured to send out emails bases on interesting mole features.
|
42
|
+
# This feature uses actionmailer. You must specify a hash for the from and to options.
|
43
|
+
# ==
|
44
|
+
# :emails => { :from => 'fred@acme.com', :to => ['blee@acme.com', 'doh@acme.com'] }
|
45
|
+
# ==
|
46
|
+
# :mail_on :: Hash for email alert triggers. May be enabled or disabled per env settings. Default is disabled
|
47
|
+
# ==
|
48
|
+
# :mail_on => {:enabled => true, :features => [Rackamole.perf, Rackamole.fault] }
|
15
49
|
def initialize( app, opts={} )
|
16
50
|
@app = app
|
17
51
|
init_options( opts )
|
52
|
+
validate_options
|
18
53
|
end
|
19
|
-
|
54
|
+
|
55
|
+
# Entering the MOle zone...
|
56
|
+
# Watches incoming requests and report usage information. The mole will also track request that
|
57
|
+
# are taking longer than expected and also report any requests that are raising exceptions.
|
20
58
|
def call( env )
|
21
59
|
# Bail if application is not moleable
|
22
60
|
return @app.call( env ) unless moleable?
|
@@ -27,27 +65,22 @@ module Rack
|
|
27
65
|
status, headers, body = @app.call( env )
|
28
66
|
rescue => boom
|
29
67
|
env['mole.exception'] = boom
|
30
|
-
|
68
|
+
mole_feature( env, elapsed, status, headers, body )
|
31
69
|
raise boom
|
32
70
|
end
|
33
71
|
end
|
34
|
-
|
72
|
+
mole_feature( env, elapsed, status, headers, body )
|
35
73
|
return status, headers, body
|
36
74
|
end
|
37
75
|
|
38
76
|
# ===========================================================================
|
39
77
|
private
|
40
78
|
|
79
|
+
attr_reader :options #:nodoc:
|
80
|
+
|
41
81
|
# Load up configuration options
|
42
82
|
def init_options( opts )
|
43
|
-
options
|
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]
|
83
|
+
@options = default_options.merge( opts )
|
51
84
|
end
|
52
85
|
|
53
86
|
# Mole default options
|
@@ -57,13 +90,61 @@ module Rack
|
|
57
90
|
:excluded_paths => [/.?\.ico/, /.?\.png/],
|
58
91
|
:moleable => true,
|
59
92
|
:perf_threshold => 10,
|
60
|
-
:store => Rackamole::Store::Log.new
|
93
|
+
:store => Rackamole::Store::Log.new,
|
94
|
+
:twitt_on => { :enabled => false, :features => [Rackamole.perf, Rackamole.fault] },
|
95
|
+
:mail_on => { :enabled => false, :features => [Rackamole.perf, Rackamole.fault] }
|
61
96
|
}
|
62
97
|
end
|
63
|
-
|
98
|
+
|
99
|
+
# Validates all configured options... Throws error if invalid configuration
|
100
|
+
def validate_options
|
101
|
+
%w[app_name moleable perf_threshold store].each do |k|
|
102
|
+
raise "[M()le] -- Unable to locate required option key `#{k}" unless options[k.to_sym]
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Send moled info to store and potentially send out alerts...
|
107
|
+
def mole_feature( env, elapsed, status, headers, body )
|
108
|
+
attrs = mole_info( env, elapsed, status, headers, body )
|
109
|
+
|
110
|
+
# send info to configured store
|
111
|
+
options[:store].mole( attrs )
|
112
|
+
|
113
|
+
# send email alert ?
|
114
|
+
if configured?( :emails, [:from, :to] ) and alertable?( options[:mail_on], attrs[:type] )
|
115
|
+
Rackamole::Alert::Emole.deliver_alert( options[:emails][:from], options[:emails][:to], attrs )
|
116
|
+
end
|
117
|
+
|
118
|
+
# send twitter alert ?
|
119
|
+
if configured?( :twitter_auth, [:username, :password] ) and alertable?( options[:twitt_on], attrs[:type] )
|
120
|
+
twitt.send_alert( attrs )
|
121
|
+
end
|
122
|
+
rescue => boom
|
123
|
+
$stderr.puts "!! MOLE RECORDING CRAPPED OUT !! -- #{boom}"
|
124
|
+
boom.backtrace.each { |l| $stderr.puts l }
|
125
|
+
end
|
126
|
+
|
127
|
+
# Check if an options is set and configured
|
128
|
+
def configured?( key, configs )
|
129
|
+
return false unless options[key]
|
130
|
+
configs.each { |c| return false unless options[key][c] }
|
131
|
+
true
|
132
|
+
end
|
133
|
+
|
134
|
+
# Check if feature should be send to alert clients ie email or twitter
|
135
|
+
def alertable?( filters, type )
|
136
|
+
return false if !filters or filters.empty? or !filters[:enabled]
|
137
|
+
filters[:features].include?( type )
|
138
|
+
end
|
139
|
+
|
140
|
+
# Create or retrieve twitter client
|
141
|
+
def twitt
|
142
|
+
@twitt ||= Rackamole::Alert::Twitt.new( options[:twitter_auth][:username], options[:twitter_auth][:password] )
|
143
|
+
end
|
144
|
+
|
64
145
|
# Check if this request should be moled according to the exclude filters
|
65
146
|
def mole_request?( request )
|
66
|
-
|
147
|
+
options[:excluded_paths].each do |exclude_path|
|
67
148
|
return false if request.path.match( exclude_path )
|
68
149
|
end
|
69
150
|
true
|
@@ -87,19 +168,21 @@ module Rack
|
|
87
168
|
|
88
169
|
# BOZO !! This could be slow if have to query db to get user name...
|
89
170
|
# Preferred store username in session and give at key
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
171
|
+
user_key = options[:user_key]
|
172
|
+
if session and user_key
|
173
|
+
if user_key.instance_of? Hash
|
174
|
+
user_id = session[ user_key[:session_key] ]
|
175
|
+
if user_key[:extractor]
|
176
|
+
user_name = user_key[:extractor].call( user_id )
|
95
177
|
end
|
96
178
|
else
|
97
|
-
user_name = session[
|
179
|
+
user_name = session[user_key]
|
98
180
|
end
|
99
181
|
end
|
100
|
-
|
101
|
-
info[:
|
102
|
-
info[:
|
182
|
+
|
183
|
+
info[:type] = (elapsed and elapsed > options[:perf_threshold] ? Rackamole.perf : Rackamole.feature)
|
184
|
+
info[:app_name] = options[:app_name]
|
185
|
+
info[:environment] = options[:environment] || "Unknown"
|
103
186
|
info[:user_id] = user_id if user_id
|
104
187
|
info[:user_name] = user_name || "Unknown"
|
105
188
|
info[:ip] = ip
|
@@ -107,7 +190,6 @@ module Rack
|
|
107
190
|
info[:host] = env['SERVER_NAME']
|
108
191
|
info[:software] = env['SERVER_SOFTWARE']
|
109
192
|
info[:request_time] = elapsed if elapsed
|
110
|
-
info[:performance] = (elapsed and elapsed > @perf_threshold)
|
111
193
|
info[:url] = request.url
|
112
194
|
info[:method] = env['REQUEST_METHOD']
|
113
195
|
info[:path] = request.path
|
@@ -129,13 +211,12 @@ module Rack
|
|
129
211
|
exception = env['mole.exception']
|
130
212
|
if exception
|
131
213
|
info[:ruby_version] = %x[ruby -v]
|
214
|
+
info[:fault] = exception.to_s
|
132
215
|
info[:stack] = trim_stack( exception )
|
216
|
+
info[:type] = Rackamole.fault
|
133
217
|
env['mole.exception'] = nil
|
134
218
|
end
|
135
219
|
info
|
136
|
-
rescue => boom
|
137
|
-
$stderr.puts "!! MOLE RECORDING CRAPPED OUT !! -- #{boom}"
|
138
|
-
boom.backtrace.each { |l| $stderr.puts l }
|
139
220
|
end
|
140
221
|
|
141
222
|
# Attempts to detect browser type from agent info.
|
@@ -162,7 +243,7 @@ module Rack
|
|
162
243
|
|
163
244
|
# Checks if this application is moleable
|
164
245
|
def moleable?
|
165
|
-
|
246
|
+
options[:moleable]
|
166
247
|
end
|
167
248
|
|
168
249
|
# Fetch route info if any...
|