mole 1.0.12 → 1.0.15
Sign up to get free protection for your applications and to get access to all the features.
- metadata +24 -146
- data/History.txt +0 -17
- data/Manifest.txt +0 -132
- data/README.txt +0 -216
- data/Rakefile +0 -46
- data/config/database.yml +0 -21
- data/config/test_database.yml +0 -69
- data/lib/mole.rb +0 -260
- data/lib/mole/db/migrate.rb +0 -90
- data/lib/mole/e_mole.rb +0 -75
- data/lib/mole/logger.rb +0 -134
- data/lib/mole/models/mole_feature.rb +0 -58
- data/lib/mole/models/mole_log.rb +0 -31
- data/lib/mole/module.rb +0 -292
- data/lib/mole/moler.rb +0 -71
- data/lib/mole/utils/frameworks.rb +0 -53
- data/lib/mole/version.rb +0 -15
- data/samples/merbapp/README +0 -14
- data/samples/merbapp/Rakefile +0 -124
- data/samples/merbapp/app/controllers/application.rb +0 -3
- data/samples/merbapp/app/controllers/exceptions.rb +0 -13
- data/samples/merbapp/app/controllers/moled.rb +0 -25
- data/samples/merbapp/app/helpers/global_helper.rb +0 -5
- data/samples/merbapp/app/mailers/views/layout/application.html.erb +0 -1
- data/samples/merbapp/app/mailers/views/layout/application.text.erb +0 -1
- data/samples/merbapp/app/parts/views/layout/application.html.erb +0 -1
- data/samples/merbapp/app/views/exceptions/internal_server_error.html.erb +0 -216
- data/samples/merbapp/app/views/exceptions/not_acceptable.html.erb +0 -38
- data/samples/merbapp/app/views/exceptions/not_found.html.erb +0 -40
- data/samples/merbapp/app/views/layout/application.html.erb +0 -11
- data/samples/merbapp/app/views/moled/index.html.erb +0 -5
- data/samples/merbapp/app/views/moled/result.html.erb +0 -5
- data/samples/merbapp/config/boot.rb +0 -11
- data/samples/merbapp/config/dependencies.rb +0 -41
- data/samples/merbapp/config/environments/development.rb +0 -1
- data/samples/merbapp/config/environments/production.rb +0 -1
- data/samples/merbapp/config/environments/test.rb +0 -1
- data/samples/merbapp/config/merb.yml +0 -82
- data/samples/merbapp/config/merb_init.rb +0 -26
- data/samples/merbapp/config/mole_config.rb +0 -33
- data/samples/merbapp/config/router.rb +0 -38
- data/samples/merbapp/config/upload.conf +0 -0
- data/samples/merbapp/public/images/merb.jpg +0 -0
- data/samples/merbapp/public/merb.fcgi +0 -6
- data/samples/merbapp/public/stylesheets/master.css +0 -119
- data/samples/merbapp/script/destroy +0 -32
- data/samples/merbapp/script/generate +0 -32
- data/samples/merbapp/script/stop_merb +0 -13
- data/samples/merbapp/spec/spec_helper.rb +0 -15
- data/samples/merbapp/test/test_helper.rb +0 -14
- data/samples/railsapp/README +0 -14
- data/samples/railsapp/Rakefile +0 -10
- data/samples/railsapp/app/controllers/application.rb +0 -13
- data/samples/railsapp/app/controllers/moled_controller.rb +0 -23
- data/samples/railsapp/app/helpers/application_helper.rb +0 -3
- data/samples/railsapp/app/views/moled/index.html.erb +0 -5
- data/samples/railsapp/app/views/moled/result.html.erb +0 -5
- data/samples/railsapp/config/boot.rb +0 -109
- data/samples/railsapp/config/database.yml +0 -13
- data/samples/railsapp/config/environment.rb +0 -59
- data/samples/railsapp/config/environments/development.rb +0 -18
- data/samples/railsapp/config/environments/production.rb +0 -20
- data/samples/railsapp/config/environments/test.rb +0 -22
- data/samples/railsapp/config/initializers/inflections.rb +0 -10
- data/samples/railsapp/config/initializers/mime_types.rb +0 -5
- data/samples/railsapp/config/initializers/mole.rb +0 -10
- data/samples/railsapp/config/moles/mole_config.rb +0 -44
- data/samples/railsapp/config/routes.rb +0 -35
- data/samples/railsapp/doc/README_FOR_APP +0 -2
- data/samples/railsapp/public/.htaccess +0 -40
- data/samples/railsapp/public/404.html +0 -30
- data/samples/railsapp/public/422.html +0 -30
- data/samples/railsapp/public/500.html +0 -30
- data/samples/railsapp/public/dispatch.cgi +0 -10
- data/samples/railsapp/public/dispatch.fcgi +0 -24
- data/samples/railsapp/public/dispatch.rb +0 -10
- data/samples/railsapp/public/favicon.ico +0 -0
- data/samples/railsapp/public/images/rails.png +0 -0
- data/samples/railsapp/public/javascripts/application.js +0 -2
- data/samples/railsapp/public/javascripts/controls.js +0 -963
- data/samples/railsapp/public/javascripts/dragdrop.js +0 -972
- data/samples/railsapp/public/javascripts/effects.js +0 -1120
- data/samples/railsapp/public/javascripts/prototype.js +0 -4225
- data/samples/railsapp/public/robots.txt +0 -5
- data/samples/railsapp/script/about +0 -3
- data/samples/railsapp/script/console +0 -3
- data/samples/railsapp/script/destroy +0 -3
- data/samples/railsapp/script/generate +0 -3
- data/samples/railsapp/script/performance/benchmarker +0 -3
- data/samples/railsapp/script/performance/profiler +0 -3
- data/samples/railsapp/script/performance/request +0 -3
- data/samples/railsapp/script/plugin +0 -3
- data/samples/railsapp/script/process/inspector +0 -3
- data/samples/railsapp/script/process/reaper +0 -3
- data/samples/railsapp/script/process/spawner +0 -3
- data/samples/railsapp/script/runner +0 -3
- data/samples/railsapp/script/server +0 -3
- data/samples/railsapp/test/test_helper.rb +0 -38
- data/samples/rubyapp/README +0 -22
- data/samples/rubyapp/bin/ruby_app +0 -35
- data/samples/rubyapp/config/mole_conf.rb +0 -31
- data/samples/rubyapp/lib/fred.rb +0 -22
- data/spec/config/auto_mole_config.rb +0 -26
- data/spec/config/mole_config.rb +0 -0
- data/spec/config/moles/fred_config.rb +0 -0
- data/spec/data/blee.rb +0 -64
- data/spec/db/migrate_spec.rb +0 -19
- data/spec/emole_spec.rb +0 -43
- data/spec/logger_spec.rb +0 -56
- data/spec/models/mole_feature_spec.rb +0 -48
- data/spec/models/mole_log_spec.rb +0 -62
- data/spec/module_spec.rb +0 -229
- data/spec/mole_spec.rb +0 -135
- data/spec/moler_spec.rb +0 -77
- data/spec/spec_helper.rb +0 -76
- data/spec/utils/framework_spec.rb +0 -99
- data/tasks/ann.rake +0 -76
- data/tasks/annotations.rake +0 -22
- data/tasks/doc.rake +0 -48
- data/tasks/gem.rake +0 -110
- data/tasks/manifest.rake +0 -49
- data/tasks/mole.rake +0 -115
- data/tasks/post_load.rake +0 -26
- data/tasks/rubyforge.rake +0 -57
- data/tasks/setup.rb +0 -227
- data/tasks/spec.rake +0 -54
- data/tasks/svn.rake +0 -44
- data/tasks/test.rake +0 -38
- data/templates/mole/e_mole/exception_alerts.rhtml +0 -14
- data/templates/mole/e_mole/feature_alerts.rhtml +0 -11
- data/templates/mole/e_mole/perf_alerts.rhtml +0 -12
data/lib/mole/e_mole.rb
DELETED
@@ -1,75 +0,0 @@
|
|
1
|
-
require 'action_mailer'
|
2
|
-
|
3
|
-
module Mole
|
4
|
-
class EMole < ActionMailer::Base
|
5
|
-
self.template_root = File.join( File.dirname(__FILE__), %w[.. .. templates] )
|
6
|
-
|
7
|
-
def setup #:nodoc:
|
8
|
-
recipients ::Mole.emole_recipients
|
9
|
-
from ::Mole.emole_from
|
10
|
-
@host = `hostname`
|
11
|
-
end
|
12
|
-
|
13
|
-
# Setup aspect
|
14
|
-
%w[perf exception feature].each do |asp|
|
15
|
-
module_eval "def #{asp}_alerts_with_setup( context, user_name, opts={} ) setup; #{asp}_alerts_without_setup( context, user_name, opts) end #:nodoc:"
|
16
|
-
end
|
17
|
-
|
18
|
-
# send out feature alerts
|
19
|
-
def feature_alerts( context, user_id, options={} )
|
20
|
-
Mole.logger.debug "Sending feature email from #{::Mole.emole_from} -- to #{::Mole.emole_recipients}"
|
21
|
-
subject "[FEATURE] #{options[:feature]} -- #{@host} -- #{Mole.application} -- #{user_id}"
|
22
|
-
body :application => Mole.application,
|
23
|
-
:host_name => @host,
|
24
|
-
:context => context.class.name,
|
25
|
-
:feature => options[:feature],
|
26
|
-
:args => dump_args( options )
|
27
|
-
end
|
28
|
-
alias_method_chain :feature_alerts, :setup
|
29
|
-
|
30
|
-
# send out mole performance alert
|
31
|
-
def perf_alerts( context, user_id, options={} )
|
32
|
-
Mole.logger.debug "Sending perf email from #{::Mole.emole_from} -- to #{::Mole.emole_recipients}"
|
33
|
-
subject "[PERF] #{@host} -- #{Mole.application} -- #{user_id}"
|
34
|
-
body :application => ::Mole.application,
|
35
|
-
:host_name => @host,
|
36
|
-
:context => context.class.name,
|
37
|
-
:feature => options[:feature],
|
38
|
-
:elapsed_time => options[:elapsed_time] ,
|
39
|
-
:args => dump_args( options )
|
40
|
-
end
|
41
|
-
alias_method_chain :perf_alerts, :setup
|
42
|
-
|
43
|
-
# send out mole exception alerts
|
44
|
-
def exception_alerts( context, user_id, options={} )
|
45
|
-
Mole.logger.debug "Sending perf email from #{::Mole.emole_from} -- to #{::Mole.emole_recipients}"
|
46
|
-
subject "[EXCEPTION] #{@host} -- #{Mole.application} -- #{user_id}"
|
47
|
-
body :application => Mole.application,
|
48
|
-
:host_name => @host,
|
49
|
-
:context => context.class.name,
|
50
|
-
:feature => options[:feature],
|
51
|
-
:boom => options[:boom],
|
52
|
-
:trace => dump_stack( options[:boom] ),
|
53
|
-
:args => dump_args( options )
|
54
|
-
end
|
55
|
-
alias_method_chain :exception_alerts, :setup
|
56
|
-
|
57
|
-
# dumps partial stack
|
58
|
-
def dump_stack( boom )
|
59
|
-
return boom if boom.is_a? String
|
60
|
-
buff = boom.backtrace[0...3].join( "\r" )
|
61
|
-
end
|
62
|
-
|
63
|
-
# dumps arguments
|
64
|
-
def dump_args( args )
|
65
|
-
return "N/A" unless args
|
66
|
-
buff = []
|
67
|
-
args.keys.sort { |a,b| a.to_s <=> b.to_s}.each do |k|
|
68
|
-
key = k.to_s.rjust(20)
|
69
|
-
value = args[k].to_s.rjust(97,".")
|
70
|
-
buff << "#{key} : #{value}"
|
71
|
-
end
|
72
|
-
buff.join( "\r" )
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
data/lib/mole/logger.rb
DELETED
@@ -1,134 +0,0 @@
|
|
1
|
-
require 'logging'
|
2
|
-
require 'forwardable'
|
3
|
-
|
4
|
-
module Mole
|
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 = ::Mole::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
|
-
|
121
|
-
# mole the bastard - create an entry into MOle log file
|
122
|
-
def log_it( context, feature, user_id, args )
|
123
|
-
args ||= "no args"
|
124
|
-
user_id ||= "N/A"
|
125
|
-
ip_addr, browser_type = MoleLog.log_details( context )
|
126
|
-
info = []
|
127
|
-
args.keys.sort { |a,b| a.to_s <=> b.to_s }.each { |k| info << "#{k}=>#{args[k]}" }
|
128
|
-
buff = ""
|
129
|
-
buff << "[#{ip_addr}/#{browser_type}]--" if ip_addr and browser_type
|
130
|
-
buff << "#{context.class.name}(#{feature}) --- #{user_id} -> #{info.join( ', ' ) }"
|
131
|
-
self.info( buff )
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
@@ -1,58 +0,0 @@
|
|
1
|
-
# Feature model - Tracks the various application features in the db.
|
2
|
-
class MoleFeature < ActiveRecord::Base
|
3
|
-
has_many :mole_logs
|
4
|
-
|
5
|
-
class << self
|
6
|
-
# famous constants...
|
7
|
-
def all() "ALL" ; end
|
8
|
-
def exception() "Exception" ; end
|
9
|
-
def performance() "Performance"; end
|
10
|
-
|
11
|
-
# find performance feature
|
12
|
-
def find_performance_feature( app_name )
|
13
|
-
find_or_create_feature( performance, app_name )
|
14
|
-
end
|
15
|
-
|
16
|
-
# find exception feature
|
17
|
-
def find_exception_feature( app_name )
|
18
|
-
find_or_create_feature( exception, app_name )
|
19
|
-
end
|
20
|
-
|
21
|
-
# Find the all feature ( wildcard feature for given app )
|
22
|
-
def find_all_feature( app_name )
|
23
|
-
find_or_create_feature( all, app_name )
|
24
|
-
end
|
25
|
-
|
26
|
-
# Find all the MOled applications
|
27
|
-
def find_moled_application_names
|
28
|
-
res = find( :all,
|
29
|
-
:select => "distinct( app_name )",
|
30
|
-
:order => "name asc" )
|
31
|
-
res.map(&:app_name)
|
32
|
-
end
|
33
|
-
|
34
|
-
# Finds all the features available for a given application
|
35
|
-
def find_features( app_name )
|
36
|
-
# Creates the all feature if necessary
|
37
|
-
find_all_feature( app_name )
|
38
|
-
find( :all,
|
39
|
-
:conditions => ["app_name = ?", app_name],
|
40
|
-
:select => "id, name, context",
|
41
|
-
:order => "name asc" )
|
42
|
-
end
|
43
|
-
|
44
|
-
# locates an existing feature or create a new one if it does not exist.
|
45
|
-
def find_or_create_feature( name, app_name, ctx_name=nil )
|
46
|
-
if name.nil? or name.empty?
|
47
|
-
::Mole.logger.error( "--- MOLE ERROR - Invalid feature. Empty or nil" )
|
48
|
-
return nil
|
49
|
-
end
|
50
|
-
if ctx_name
|
51
|
-
res = find_by_name_and_context_and_app_name( name, ctx_name, app_name )
|
52
|
-
else
|
53
|
-
res = find_by_name_and_app_name( name, app_name )
|
54
|
-
end
|
55
|
-
res || create(:name => name,:context => ctx_name, :app_name => app_name )
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
data/lib/mole/models/mole_log.rb
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
# Log Model - Tracks and record user interactions with various features
|
2
|
-
# This will make it easy to write an app on top on the MOle to track a
|
3
|
-
# particular application utilization.
|
4
|
-
class MoleLog < ActiveRecord::Base
|
5
|
-
belongs_to :mole_feature
|
6
|
-
|
7
|
-
class << self
|
8
|
-
# mole the bastard - create db entry into mole logs
|
9
|
-
def log_it( context, feature, user_id, args )
|
10
|
-
args ||= "no args"
|
11
|
-
user_id ||= "N/A"
|
12
|
-
ip_addr, browser_type = log_details( context )
|
13
|
-
MoleLog.create( :mole_feature => feature,
|
14
|
-
:user_id => user_id,
|
15
|
-
:host_name => `hostname`,
|
16
|
-
:params => args.to_yaml,
|
17
|
-
:ip_address => ip_addr,
|
18
|
-
:browser_type => browser_type )
|
19
|
-
end
|
20
|
-
|
21
|
-
# extract orginating ip address and browser type
|
22
|
-
def log_details( context ) #:nodoc:
|
23
|
-
ip_addr, browser_type = nil
|
24
|
-
if context.respond_to? :request
|
25
|
-
ip_addr, browser_type = context.request.env['REMOTE_ADDR'], context.request.env['HTTP_USER_AGENT']
|
26
|
-
end
|
27
|
-
return ip_addr, browser_type
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
end
|
data/lib/mole/module.rb
DELETED
@@ -1,292 +0,0 @@
|
|
1
|
-
# =============================================================================
|
2
|
-
# Extends module to inject interceptors
|
3
|
-
# =============================================================================
|
4
|
-
require 'benchmark'
|
5
|
-
require 'active_support'
|
6
|
-
|
7
|
-
class Module
|
8
|
-
# intercepts a collection of features and wrap performance check based on the
|
9
|
-
# specified :perf_threshold. The trigger defaults to 5 secs if not explicitly set.
|
10
|
-
#
|
11
|
-
# Example:
|
12
|
-
#
|
13
|
-
# MyClass.mole_perf do |context, action, elapsed_time, ret, block, *args|
|
14
|
-
# Mole::DbMole.perf_it( context.session[:user_id],
|
15
|
-
# :controller => context.class.name,
|
16
|
-
# :action => action,
|
17
|
-
# :elapsed_time => "%3.3f" % elapsed_time )
|
18
|
-
# end
|
19
|
-
#
|
20
|
-
# This will trap all public methods on the MyClass that takes more than
|
21
|
-
# :perf_threshold to complete. You can override this default by using the option
|
22
|
-
# :features => [m1,m2,...]. This is handy for controller moling rails
|
23
|
-
# and merb context.
|
24
|
-
#
|
25
|
-
# If you elect not to use the block form of the call, you can pass in the
|
26
|
-
# following arguments to the option hash:
|
27
|
-
# <tt>:interceptor</tt>:: The class name of your interceptor class
|
28
|
-
# <tt>:method</tt>:: The name of the method to callback the interceptor on
|
29
|
-
# once a perf condition has been trapped.
|
30
|
-
def mole_perf( opts={}, &interceptor )
|
31
|
-
opts[:interceptor] ||= interceptor
|
32
|
-
opts[:method] ||= :call
|
33
|
-
opts[:features] ||= instance_methods( false )
|
34
|
-
opts[:features].each do |feature|
|
35
|
-
wrap feature
|
36
|
-
perf_mole_filters[feature.to_s] << [opts[:interceptor], opts[:method]]
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
# monitors a collections of features and wrap rescue logic to trap unchecked
|
41
|
-
# exceptions. You can handle to trap differently by either logging the event
|
42
|
-
# in the db or sending out email/IM notification.
|
43
|
-
#
|
44
|
-
# Example:
|
45
|
-
#
|
46
|
-
# MyClass.mole_unchecked do |context, action, boom, block, *args|
|
47
|
-
# Mole::Moler.check_it( context.session[:user_id],
|
48
|
-
# :controller => context.class.name,
|
49
|
-
# :action => action,
|
50
|
-
# :boom => boom )
|
51
|
-
# end
|
52
|
-
#
|
53
|
-
# This will wrap all public instance methods on MyClass. If any of these methods
|
54
|
-
# raises an unchecked exception, the MOle will surface the condition.
|
55
|
-
# This call also takes in a :features option to specify a list of methods if the
|
56
|
-
# default instance methods is not suitable, you can pass in a collection of methods
|
57
|
-
# that you wish to mole. This is handy in the case of Rails/Merb where conveniences
|
58
|
-
# are provided to gather controller actions
|
59
|
-
#
|
60
|
-
# If you elect not to use the block form of the call, you can pass in the
|
61
|
-
# following arguments to the option hash:
|
62
|
-
# <tt>:interceptor</tt>:: The class name of your interceptor class
|
63
|
-
# <tt>:method</tt>:: The name of the method to callback the interceptor on
|
64
|
-
# once an exception condition has been trapped.
|
65
|
-
def mole_unchecked( opts={}, &interceptor )
|
66
|
-
opts[:interceptor] ||= interceptor
|
67
|
-
opts[:method] ||= :call
|
68
|
-
opts[:features] ||= instance_methods( false )
|
69
|
-
opts[:features].each do |feature|
|
70
|
-
wrap feature
|
71
|
-
unchecked_mole_filters[feature.to_s] << [opts[:interceptor], opts[:method]]
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
# intercepts a feature before the feature is called. During the callback
|
76
|
-
# you will have access to the object ( context ) on which the call is intercepted,
|
77
|
-
# as well as the arguments/block, the feature was issued with.
|
78
|
-
#
|
79
|
-
# Example:
|
80
|
-
#
|
81
|
-
# MyClass.mole_before( :feature => :blee ) do |context, feature, block, *args|
|
82
|
-
# Mole::Moler.mole_it( context, feature, context.session[:user_id],
|
83
|
-
# :args => args )
|
84
|
-
# end
|
85
|
-
#
|
86
|
-
# This will wrap the method blee with a before interceptor. Before the blee call
|
87
|
-
# is issued on MyClass, control will be handed to the before interceptor.
|
88
|
-
#
|
89
|
-
# Options:
|
90
|
-
# <tt>:feature</tt>:: The name of the feature to be intercepted
|
91
|
-
# If you elect not to use the block form of the call, you can pass in the
|
92
|
-
# following arguments to the option hash:
|
93
|
-
# <tt>:interceptor</tt>:: The class name of your interceptor class. If no interceptor block is specified
|
94
|
-
# <tt>:method</tt>:: The name of the method to callback the interceptor on
|
95
|
-
# once an exception condition has been trapped.
|
96
|
-
def mole_before(opts={}, &interceptor)
|
97
|
-
raise "Missing :feature option" if opts[:feature].nil? or opts[:feature].to_s.empty?
|
98
|
-
opts[:interceptor] ||= interceptor
|
99
|
-
opts[:method] ||= :call
|
100
|
-
feature = opts[:feature].to_s
|
101
|
-
if before_mole_filters[feature].empty?
|
102
|
-
wrap feature
|
103
|
-
before_mole_filters[feature] << [opts[:interceptor], opts[:method]]
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
# intercepts a feature after the feature is called. During the callback
|
108
|
-
# you will have access to the object ( context ) on which the call is intercepted,
|
109
|
-
# as well as the arguments/block and return values the feature was issued with.
|
110
|
-
#
|
111
|
-
# Example:
|
112
|
-
#
|
113
|
-
# MyClass.mole_after( :feature => :blee ) do |context, feature, ret_val, block, *args|
|
114
|
-
# Mole::Moler.mole_it( context, feature, context.session[:user_id],
|
115
|
-
# :args => args )
|
116
|
-
# end
|
117
|
-
#
|
118
|
-
# This will wrap the method blee with an after interceptor. After the blee call
|
119
|
-
# is issued on MyClass, control will be handed to the after interceptor.
|
120
|
-
#
|
121
|
-
# Options:
|
122
|
-
# <tt>:feature</tt>:: The name of the feature to be intercepted
|
123
|
-
# <tt>:interceptor</tt>:: The class name of your interceptor class. If no interceptor block is specified
|
124
|
-
# <tt>:method</tt>:: The name of the method to callback the interceptor on
|
125
|
-
# once an exception condition has been trapped.
|
126
|
-
def mole_after(opts = {}, &interceptor)
|
127
|
-
raise "Missing :feature option" if opts[:feature].nil? or opts[:feature].to_s.empty?
|
128
|
-
opts[:interceptor] ||= interceptor
|
129
|
-
opts[:method] ||= :call
|
130
|
-
feature = opts[:feature].to_s
|
131
|
-
if after_mole_filters[feature].empty?
|
132
|
-
wrap feature
|
133
|
-
after_mole_filters[feature] << [opts[:interceptor], opts[:method]]
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
# ---------------------------------------------------------------------------
|
138
|
-
# Dumps moled feature info
|
139
|
-
def mole_dump( msg=nil )
|
140
|
-
puts "\n------------------------------------------------------------------"
|
141
|
-
puts "From #{msg}" if msg
|
142
|
-
puts "MOle Info for class <- #{self} ->"
|
143
|
-
puts "\nBefore filters"
|
144
|
-
before_mole_filters.keys.sort.each { |k| puts "\t#{k} --> #{before_mole_filters[k]}" }
|
145
|
-
puts "\nAfter filters"
|
146
|
-
after_mole_filters.keys.sort.each { |k| puts "\t#{k} --> #{after_mole_filters[k]}" }
|
147
|
-
puts "\nUnchecked filters"
|
148
|
-
unchecked_mole_filters.keys.sort.each { |k| puts "\t#{k} --> #{unchecked_mole_filters[k]}" }
|
149
|
-
puts "\nPerf filters"
|
150
|
-
perf_mole_filters.keys.sort.each { |k| puts "\t#{k} --> #{perf_mole_filters[k]}" }
|
151
|
-
puts "---------------------------------------------------------------------\n"
|
152
|
-
end
|
153
|
-
|
154
|
-
# ===========================================================================
|
155
|
-
private
|
156
|
-
|
157
|
-
# Strip out all invalid punctuation
|
158
|
-
def clean_method_name( method )
|
159
|
-
return method.to_s.sub(/([?!=])$/, ''), $1
|
160
|
-
end
|
161
|
-
|
162
|
-
# Clear MOle state for this class # Used for testing only
|
163
|
-
def mole_clear!
|
164
|
-
@before_mole_filters = nil
|
165
|
-
@after_mole_filters = nil
|
166
|
-
@perf_mole_filters = nil
|
167
|
-
@unchecked_mole_filters = nil
|
168
|
-
end
|
169
|
-
|
170
|
-
# ===========================================================================
|
171
|
-
public
|
172
|
-
|
173
|
-
# -------------------------------------------------------------------------
|
174
|
-
# Holds before filters
|
175
|
-
def before_mole_filters #:nodoc:
|
176
|
-
@before_mole_filters ||= Hash.new{ |h,k| h[k] = [] }
|
177
|
-
end
|
178
|
-
|
179
|
-
# -------------------------------------------------------------------------
|
180
|
-
# Holds after filters
|
181
|
-
def after_mole_filters #:nodoc:
|
182
|
-
@after_mole_filters ||= Hash.new{ |h,k| h[k] = [] }
|
183
|
-
end
|
184
|
-
|
185
|
-
# -------------------------------------------------------------------------
|
186
|
-
# Holds perf around filters
|
187
|
-
def perf_mole_filters #:nodoc:
|
188
|
-
@perf_mole_filters ||= Hash.new{ |h,k| h[k] = []}
|
189
|
-
end
|
190
|
-
|
191
|
-
# -------------------------------------------------------------------------
|
192
|
-
# Holds unchecked exception filters
|
193
|
-
def unchecked_mole_filters #:nodoc:
|
194
|
-
@unchecked_mole_filters ||= Hash.new{ |h,k| h[k] = []}
|
195
|
-
end
|
196
|
-
|
197
|
-
# -------------------------------------------------------------------------
|
198
|
-
# Attempt to find singleton class method with given name
|
199
|
-
# TODO Figure out how to get method for static signature...
|
200
|
-
# def find_public_class_method(method)
|
201
|
-
# singleton_methods.each { |name| puts "Looking for #{method}--#{method.class} -- #{name}#{name.class}";return name if name == method }
|
202
|
-
# nil
|
203
|
-
# end
|
204
|
-
|
205
|
-
# -------------------------------------------------------------------------
|
206
|
-
# Wrap method call
|
207
|
-
# TODO Add support for wrapping class methods ??
|
208
|
-
def wrap( method ) #:nodoc:
|
209
|
-
return if wrapped?( method )
|
210
|
-
begin
|
211
|
-
between = instance_method( method )
|
212
|
-
rescue
|
213
|
-
# between = find_public_class_method( method )
|
214
|
-
raise "Unable to find moled feature `#{method}" unless(between)
|
215
|
-
end
|
216
|
-
method_name, punctuation = clean_method_name( method )
|
217
|
-
code = <<-code
|
218
|
-
def #{method_name}_with_mole#{punctuation} (*a, &b)
|
219
|
-
key = '#{method}'
|
220
|
-
klass = self.class
|
221
|
-
between = klass.wrapped[key]
|
222
|
-
ret_val = nil
|
223
|
-
klass.apply_before_filters( klass.before_mole_filters[key], self, key, *a, &b ) if klass.before_mole_filters[key]
|
224
|
-
begin
|
225
|
-
elapsed = Benchmark::realtime do
|
226
|
-
ret_val = between.bind(self).call( *a, &b )
|
227
|
-
end
|
228
|
-
klass.apply_perf_filters( elapsed, klass.perf_mole_filters[key], self, key, ret_val, *a, &b ) if klass.perf_mole_filters[key]
|
229
|
-
rescue => boom
|
230
|
-
klass.apply_unchecked_filters( boom, klass.unchecked_mole_filters[key], self, key, *a, &b ) if klass.unchecked_mole_filters[key]
|
231
|
-
raise boom
|
232
|
-
end
|
233
|
-
klass.apply_after_filters( klass.after_mole_filters[key], self, key, ret_val, *a, &b ) if klass.after_mole_filters[key]
|
234
|
-
ret_val
|
235
|
-
end
|
236
|
-
code
|
237
|
-
|
238
|
-
module_eval code
|
239
|
-
alias_method_chain method, "mole"
|
240
|
-
wrapped[method.to_s] = between
|
241
|
-
end
|
242
|
-
|
243
|
-
def apply_before_filters( filters, clazz, key, *a, &b ) #:nodoc:
|
244
|
-
begin
|
245
|
-
filters.each { |r,m| r.send( m, clazz, key, b, *a ) }
|
246
|
-
rescue => ca_boom
|
247
|
-
::Mole.logger.error ">>> MOle Failure: Before-Filter -- " + ca_boom
|
248
|
-
ca_boom.backtrace.each { |l| ::Mole.logger.error l }
|
249
|
-
end
|
250
|
-
end
|
251
|
-
|
252
|
-
def apply_after_filters( filters, clazz, key, ret_val, *a, &b ) #:nodoc:
|
253
|
-
begin
|
254
|
-
filters.each { |r,m| r.send( m, clazz, key, ret_val, b, *a ) }
|
255
|
-
rescue => ca_boom
|
256
|
-
::Mole.logger.error ">>> MOle Failure: After-Filter -- " + ca_boom
|
257
|
-
ca_boom.backtrace.each { |l| ::Mole.logger.error l }
|
258
|
-
end
|
259
|
-
end
|
260
|
-
|
261
|
-
def apply_perf_filters( elapsed, filters, clazz, key, ret_val, *a, &b ) #:nodoc:
|
262
|
-
begin
|
263
|
-
if ( elapsed >= Mole.perf_threshold )
|
264
|
-
filters.each { |r,m| r.send( m, clazz, key, elapsed, ret_val, b, *a ) }
|
265
|
-
end
|
266
|
-
rescue => ca_boom
|
267
|
-
::Mole.logger.error ">>> MOle Failure: Perf-Filter -- " + ca_boom
|
268
|
-
ca_boom.backtrace.each { |l| ::Mole.logger.error l }
|
269
|
-
end
|
270
|
-
end
|
271
|
-
|
272
|
-
def apply_unchecked_filters( boom, filters, clazz, key, *a, &b ) #:nodoc:
|
273
|
-
begin
|
274
|
-
filters.each { |r,m| r.send( m, clazz, key, boom, b, *a ) }
|
275
|
-
rescue => ca_boom
|
276
|
-
::Mole.logger.error ">>> MOle Failure: Unchecked-Filter -- " + ca_boom
|
277
|
-
ca_boom.backtrace.each { |l| ::Mole.logger.error l }
|
278
|
-
end
|
279
|
-
end
|
280
|
-
|
281
|
-
# ---------------------------------------------------------------------------
|
282
|
-
# Log wrapped class
|
283
|
-
def wrapped #:nodoc:
|
284
|
-
@wrapped ||= {}
|
285
|
-
end
|
286
|
-
|
287
|
-
# ---------------------------------------------------------------------------
|
288
|
-
# Check if method has been wrapped
|
289
|
-
def wrapped?(which) #:nodoc:
|
290
|
-
wrapped.has_key?(which.to_s)
|
291
|
-
end
|
292
|
-
end
|