derailed-mole 1.0.10
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +17 -0
- data/Manifest.txt +137 -0
- data/README.txt +216 -0
- data/Rakefile +46 -0
- data/bin/molify +64 -0
- data/config/database.yml +21 -0
- data/config/test_database.yml +69 -0
- data/lib/mole.rb +260 -0
- data/lib/mole/db/migrate.rb +90 -0
- data/lib/mole/e_mole.rb +75 -0
- data/lib/mole/e_mole_helper.rb +2 -0
- data/lib/mole/logger.rb +134 -0
- data/lib/mole/models/mole_feature.rb +58 -0
- data/lib/mole/models/mole_log.rb +31 -0
- data/lib/mole/module.rb +292 -0
- data/lib/mole/moler.rb +71 -0
- data/lib/mole/utils/frameworks.rb +53 -0
- data/lib/mole/version.rb +15 -0
- data/mole.gemspec +37 -0
- data/samples/merbapp/README +14 -0
- data/samples/merbapp/Rakefile +124 -0
- data/samples/merbapp/app/controllers/application.rb +3 -0
- data/samples/merbapp/app/controllers/exceptions.rb +13 -0
- data/samples/merbapp/app/controllers/moled.rb +25 -0
- data/samples/merbapp/app/helpers/global_helper.rb +5 -0
- data/samples/merbapp/app/mailers/views/layout/application.html.erb +1 -0
- data/samples/merbapp/app/mailers/views/layout/application.text.erb +1 -0
- data/samples/merbapp/app/parts/views/layout/application.html.erb +1 -0
- data/samples/merbapp/app/views/exceptions/internal_server_error.html.erb +216 -0
- data/samples/merbapp/app/views/exceptions/not_acceptable.html.erb +38 -0
- data/samples/merbapp/app/views/exceptions/not_found.html.erb +40 -0
- data/samples/merbapp/app/views/layout/application.html.erb +11 -0
- data/samples/merbapp/app/views/moled/index.html.erb +5 -0
- data/samples/merbapp/app/views/moled/result.html.erb +5 -0
- data/samples/merbapp/config/boot.rb +11 -0
- data/samples/merbapp/config/dependencies.rb +41 -0
- data/samples/merbapp/config/environments/development.rb +1 -0
- data/samples/merbapp/config/environments/production.rb +1 -0
- data/samples/merbapp/config/environments/test.rb +1 -0
- data/samples/merbapp/config/merb.yml +82 -0
- data/samples/merbapp/config/merb_init.rb +26 -0
- data/samples/merbapp/config/mole_config.rb +33 -0
- data/samples/merbapp/config/router.rb +38 -0
- data/samples/merbapp/config/upload.conf +0 -0
- data/samples/merbapp/public/images/merb.jpg +0 -0
- data/samples/merbapp/public/merb.fcgi +6 -0
- data/samples/merbapp/public/stylesheets/master.css +119 -0
- data/samples/merbapp/script/destroy +32 -0
- data/samples/merbapp/script/generate +32 -0
- data/samples/merbapp/script/stop_merb +13 -0
- data/samples/merbapp/spec/spec_helper.rb +15 -0
- data/samples/merbapp/test/test_helper.rb +14 -0
- data/samples/railsapp/README +14 -0
- data/samples/railsapp/Rakefile +10 -0
- data/samples/railsapp/app/controllers/application.rb +13 -0
- data/samples/railsapp/app/controllers/moled_controller.rb +24 -0
- data/samples/railsapp/app/helpers/application_helper.rb +3 -0
- data/samples/railsapp/app/views/moled/index.html.erb +5 -0
- data/samples/railsapp/app/views/moled/result.html.erb +5 -0
- data/samples/railsapp/config/boot.rb +109 -0
- data/samples/railsapp/config/database.yml +13 -0
- data/samples/railsapp/config/environment.rb +59 -0
- data/samples/railsapp/config/environments/development.rb +18 -0
- data/samples/railsapp/config/environments/production.rb +20 -0
- data/samples/railsapp/config/environments/test.rb +22 -0
- data/samples/railsapp/config/initializers/inflections.rb +10 -0
- data/samples/railsapp/config/initializers/mime_types.rb +5 -0
- data/samples/railsapp/config/initializers/mole.rb +10 -0
- data/samples/railsapp/config/moles/mole_config.rb +44 -0
- data/samples/railsapp/config/routes.rb +35 -0
- data/samples/railsapp/doc/README_FOR_APP +2 -0
- data/samples/railsapp/public/.htaccess +40 -0
- data/samples/railsapp/public/404.html +30 -0
- data/samples/railsapp/public/422.html +30 -0
- data/samples/railsapp/public/500.html +30 -0
- data/samples/railsapp/public/dispatch.cgi +10 -0
- data/samples/railsapp/public/dispatch.fcgi +24 -0
- data/samples/railsapp/public/dispatch.rb +10 -0
- data/samples/railsapp/public/favicon.ico +0 -0
- data/samples/railsapp/public/images/rails.png +0 -0
- data/samples/railsapp/public/javascripts/application.js +2 -0
- data/samples/railsapp/public/javascripts/controls.js +963 -0
- data/samples/railsapp/public/javascripts/dragdrop.js +972 -0
- data/samples/railsapp/public/javascripts/effects.js +1120 -0
- data/samples/railsapp/public/javascripts/prototype.js +4225 -0
- data/samples/railsapp/public/robots.txt +5 -0
- data/samples/railsapp/script/about +3 -0
- data/samples/railsapp/script/console +3 -0
- data/samples/railsapp/script/destroy +3 -0
- data/samples/railsapp/script/generate +3 -0
- data/samples/railsapp/script/performance/benchmarker +3 -0
- data/samples/railsapp/script/performance/profiler +3 -0
- data/samples/railsapp/script/performance/request +3 -0
- data/samples/railsapp/script/plugin +3 -0
- data/samples/railsapp/script/process/inspector +3 -0
- data/samples/railsapp/script/process/reaper +3 -0
- data/samples/railsapp/script/process/spawner +3 -0
- data/samples/railsapp/script/runner +3 -0
- data/samples/railsapp/script/server +3 -0
- data/samples/railsapp/test/test_helper.rb +38 -0
- data/samples/rubyapp/README +22 -0
- data/samples/rubyapp/bin/ruby_app +35 -0
- data/samples/rubyapp/config/mole_conf.rb +31 -0
- data/samples/rubyapp/lib/fred.rb +22 -0
- data/spec/config/auto_mole_config.rb +26 -0
- data/spec/config/mole_config.rb +0 -0
- data/spec/config/moles/fred_config.rb +0 -0
- data/spec/data/blee.rb +64 -0
- data/spec/db/migrate_spec.rb +19 -0
- data/spec/emole_spec.rb +43 -0
- data/spec/logger_spec.rb +56 -0
- data/spec/models/mole_feature_spec.rb +48 -0
- data/spec/models/mole_log_spec.rb +62 -0
- data/spec/module_spec.rb +229 -0
- data/spec/mole_spec.rb +135 -0
- data/spec/moler_spec.rb +77 -0
- data/spec/spec_helper.rb +76 -0
- data/spec/utils/framework_spec.rb +99 -0
- data/tasks/ann.rake +76 -0
- data/tasks/annotations.rake +22 -0
- data/tasks/doc.rake +48 -0
- data/tasks/gem.rake +110 -0
- data/tasks/manifest.rake +49 -0
- data/tasks/mole.rake +115 -0
- data/tasks/post_load.rake +26 -0
- data/tasks/rubyforge.rake +57 -0
- data/tasks/setup.rb +227 -0
- data/tasks/spec.rake +54 -0
- data/tasks/svn.rake +44 -0
- data/tasks/test.rake +38 -0
- data/templates/mole/e_mole/exception_alerts.rhtml +14 -0
- data/templates/mole/e_mole/feature_alerts.rhtml +11 -0
- data/templates/mole/e_mole/perf_alerts.rhtml +12 -0
- metadata +206 -0
data/config/database.yml
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# ------------------------ Databases ------------------------
|
2
|
+
#
|
3
|
+
# Local login
|
4
|
+
local: &local
|
5
|
+
adapter: mysql
|
6
|
+
host: localhost
|
7
|
+
username: root
|
8
|
+
password:
|
9
|
+
|
10
|
+
local_dev: &local_dev
|
11
|
+
<<: *local
|
12
|
+
database: mole_dev
|
13
|
+
|
14
|
+
local_test: &local_test
|
15
|
+
<<: *local
|
16
|
+
database: mole_test
|
17
|
+
|
18
|
+
# ------------------------ Environments ------------------------
|
19
|
+
#
|
20
|
+
development: *local_dev
|
21
|
+
test: *local_test
|
@@ -0,0 +1,69 @@
|
|
1
|
+
#
|
2
|
+
# ------------------------ Databases ------------------------
|
3
|
+
#
|
4
|
+
|
5
|
+
# Production read-only
|
6
|
+
read_only: &read_only
|
7
|
+
adapter: mysql
|
8
|
+
host: 10.10.12.100
|
9
|
+
database: ci_sentiment_db
|
10
|
+
username: ciro
|
11
|
+
password: ciro
|
12
|
+
|
13
|
+
# Production writable
|
14
|
+
writable: &writable
|
15
|
+
adapter: mysql
|
16
|
+
host: 10.10.12.101
|
17
|
+
database: ci_sentiment_db
|
18
|
+
username: ciprod
|
19
|
+
password: ciprod
|
20
|
+
|
21
|
+
# Remote development database
|
22
|
+
dev2: &dev2
|
23
|
+
adapter: mysql
|
24
|
+
host: dev2
|
25
|
+
encoding: utf8
|
26
|
+
database: ci_sentiment_db
|
27
|
+
username: root
|
28
|
+
password: alchem1st
|
29
|
+
|
30
|
+
# CC test database
|
31
|
+
cc: &cc
|
32
|
+
adapter: mysql
|
33
|
+
host: 10.10.14.105
|
34
|
+
encoding: utf8
|
35
|
+
database: sentiment_test
|
36
|
+
username: root
|
37
|
+
password: alchem1st
|
38
|
+
|
39
|
+
# Local login
|
40
|
+
local: &local
|
41
|
+
adapter: mysql
|
42
|
+
host: localhost
|
43
|
+
username: root
|
44
|
+
password:
|
45
|
+
|
46
|
+
local_dev: &local_dev
|
47
|
+
<<: *local
|
48
|
+
database: sentiment_dev
|
49
|
+
|
50
|
+
local_test: &local_test
|
51
|
+
<<: *local
|
52
|
+
database: sentiment_test
|
53
|
+
|
54
|
+
yahoo: &yahoo
|
55
|
+
adapter: mysql
|
56
|
+
database: ci_yahoo_db
|
57
|
+
host: 10.10.12.104
|
58
|
+
username: ciprod
|
59
|
+
password: ciprod
|
60
|
+
#
|
61
|
+
# ------------------------ Environments ------------------------
|
62
|
+
#
|
63
|
+
development: *local_dev
|
64
|
+
test: *local_test
|
65
|
+
beta: *dev2
|
66
|
+
production: *writable
|
67
|
+
cc: *cc
|
68
|
+
yahoo_production: *yahoo
|
69
|
+
production_ro: *read_only
|
data/lib/mole.rb
ADDED
@@ -0,0 +1,260 @@
|
|
1
|
+
# $Id$
|
2
|
+
|
3
|
+
# Equivalent to a header guard in C/C++
|
4
|
+
# Used to prevent the class/module from being loaded more than once
|
5
|
+
unless defined? Mole
|
6
|
+
require 'activerecord'
|
7
|
+
module Mole
|
8
|
+
# :stopdoc:
|
9
|
+
LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
|
10
|
+
PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
|
11
|
+
|
12
|
+
# :startdoc:
|
13
|
+
# The MOle can be ran in a couple of modes: Transient and Persistent
|
14
|
+
# Transient mode will log the output to the specified log file
|
15
|
+
# Persistent mode will log the mole output to your db
|
16
|
+
# The default is :transient
|
17
|
+
def self.run_modes #:nodoc:
|
18
|
+
[:transient, :persistent]
|
19
|
+
end
|
20
|
+
|
21
|
+
# MOle Default settings
|
22
|
+
def self.defaults #:nodoc:
|
23
|
+
@defaults ||= {
|
24
|
+
:moleable => false,
|
25
|
+
:application => "Default",
|
26
|
+
:perf_threshold => 5,
|
27
|
+
:mode => :transient,
|
28
|
+
:emole_from => "MOleBeatch",
|
29
|
+
:emole_recipients => [],
|
30
|
+
:mole_config => nil,
|
31
|
+
# logging options
|
32
|
+
:log_file => $stdout,
|
33
|
+
:log_level => :info,
|
34
|
+
:email_alerts_to => "MOleBeatch",
|
35
|
+
:email_alert_level => :error }
|
36
|
+
end
|
37
|
+
|
38
|
+
# Reset the configuration to what it would be when the class is parsed
|
39
|
+
# this is needed mainly for running specs. This resets the class to the
|
40
|
+
# state it was before initialize is called. initialize MUST be called
|
41
|
+
# after reset_configuration! is invoked
|
42
|
+
def self.reset_configuration! #:nodoc:
|
43
|
+
@logger.clear_appenders if @logger
|
44
|
+
@logger = nil
|
45
|
+
@config = nil
|
46
|
+
end
|
47
|
+
|
48
|
+
# Initialize the MOle
|
49
|
+
# Valid options are
|
50
|
+
# <tt>moleable</tt>:: specify if this application is moleable.
|
51
|
+
# Defaults to false.
|
52
|
+
# <tt>application</tt>:: the name of the application to be moled.
|
53
|
+
# <tt>perf_threshold</tt>:: the performance threshold over which a Mole condition will be issued.
|
54
|
+
# Defaults to 5 seconds
|
55
|
+
# <tt>mode</tt>:: the MOle logging mole. The mole can either log information to a db via
|
56
|
+
# the :persistent option or to a log file via the :transient flag.
|
57
|
+
# Defaults to transient
|
58
|
+
# <tt>emole_from</tt>:: the EMole originator when sending eMOle alerts.
|
59
|
+
# <tt>emole_recipients</tt>:: a collection of EMOle recipients
|
60
|
+
# <tt>mole_config</tt>:: the location of the MOle configuration file where the interceptors will
|
61
|
+
# be defined.
|
62
|
+
# <tt>log_file</tt>:: The log file to be used to log MOle interceptions
|
63
|
+
# <tt>log_level</tt>:: logging level ie :info, :debug, :error, :warn...
|
64
|
+
# <tt>email_alerts_to</tt>:: log level email alert recipients.
|
65
|
+
# <tt>email_alert_level</tt>:: specifies which log level will trigger email alerts to be sent
|
66
|
+
def self.initialize( opts={} )
|
67
|
+
@config = defaults.merge( opts )
|
68
|
+
@config[:email_alerts_to] = @config[:emole_recipients] if @config[:emole_recipients] and !@config[:emole_recipients].empty?
|
69
|
+
# Add the mole/lib to the ruby path...
|
70
|
+
$: << libpath
|
71
|
+
Mole.require_all_libs_relative_to __FILE__
|
72
|
+
end
|
73
|
+
|
74
|
+
# Loads the mole configuration file
|
75
|
+
# You can either specify a directory containing mole config files or
|
76
|
+
# a single mole config file via the mole_config option.
|
77
|
+
def self.load_mole_configuration
|
78
|
+
return unless moleable?
|
79
|
+
raise "Unable to find the MOle configuration from `#{conf_file}" if conf_file and !File.exists? conf_file
|
80
|
+
unless @config_loaded
|
81
|
+
@config_loader = true
|
82
|
+
if File.directory? conf_file
|
83
|
+
logger.debug "--- Loading MOle configs files from directory `#{conf_file}"
|
84
|
+
load_all_moles_relative_to( conf_file )
|
85
|
+
else
|
86
|
+
logger.debug "--- Loading single MOle config #{conf_file}"
|
87
|
+
load conf_file
|
88
|
+
end
|
89
|
+
end
|
90
|
+
@config_loaded
|
91
|
+
end
|
92
|
+
|
93
|
+
# Fetch the MOle configuration file
|
94
|
+
def self.conf_file #:nodoc:
|
95
|
+
config[:mole_config]
|
96
|
+
end
|
97
|
+
|
98
|
+
# EMole alert sender
|
99
|
+
def self.emole_from #:nodoc:
|
100
|
+
config[:emole_from]
|
101
|
+
end
|
102
|
+
|
103
|
+
# EMole alert recipients
|
104
|
+
def self.emole_recipients #:nodoc:
|
105
|
+
config[:emole_recipients]
|
106
|
+
end
|
107
|
+
|
108
|
+
# Fetch the MOle configuration
|
109
|
+
def self.config #:nodoc:
|
110
|
+
@config
|
111
|
+
end
|
112
|
+
|
113
|
+
# Debug
|
114
|
+
def self.dump #:nodoc:
|
115
|
+
puts ""
|
116
|
+
puts "Mole Configuration Landscape"
|
117
|
+
config.keys.sort{ |a,b| a.to_s <=> b.to_s }.each do |k|
|
118
|
+
key = k.to_s.rjust(20)
|
119
|
+
value = config[k].to_s.rjust(97,".")
|
120
|
+
puts "#{key} : #{value}"
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# get a hold of a logger. This is the global logger for sentiment.
|
125
|
+
def self.logger #:nodoc:
|
126
|
+
@logger ||= ::Mole::Logger.new( { :log_file => config[:log_file],
|
127
|
+
:logger_name => "MOle",
|
128
|
+
:log_level => config[:log_level],
|
129
|
+
:email_alerts_to => config[:email_alerts_to],
|
130
|
+
:email_alert_level => config[:email_alert_level],
|
131
|
+
:additive => false } )
|
132
|
+
end
|
133
|
+
|
134
|
+
# The name of the MOled application
|
135
|
+
def self.application #:nodoc:
|
136
|
+
config[:application]
|
137
|
+
end
|
138
|
+
|
139
|
+
# Is this application is MOleable
|
140
|
+
def self.moleable? #:nodoc:
|
141
|
+
config[:moleable]
|
142
|
+
end
|
143
|
+
|
144
|
+
# Returns the MOle perf threshold. If any MOled features takes longer
|
145
|
+
# than this time to complete, then an alarm will be triggered...
|
146
|
+
def self.perf_threshold #:nodoc:
|
147
|
+
config[:perf_threshold]
|
148
|
+
end
|
149
|
+
|
150
|
+
# Enable to toggle between different log modes ie :persistent/:transient
|
151
|
+
def self.switch_mode( mode )
|
152
|
+
config[:mode] = mode
|
153
|
+
end
|
154
|
+
|
155
|
+
# Check if the MOle is running in persistent mode
|
156
|
+
def self.persistent?
|
157
|
+
config[:mode] == :persistent
|
158
|
+
end
|
159
|
+
|
160
|
+
# Returns the library path for the module. If any arguments are given,
|
161
|
+
# they will be joined to the end of the libray path using
|
162
|
+
# <tt>File.join</tt>.
|
163
|
+
#
|
164
|
+
def self.libpath( *args ) #:nodoc:
|
165
|
+
args.empty? ? LIBPATH : ::File.join(LIBPATH, *args)
|
166
|
+
end
|
167
|
+
|
168
|
+
# Returns the lpath for the module. If any arguments are given,
|
169
|
+
# they will be joined to the end of the path using
|
170
|
+
# <tt>File.join</tt>.
|
171
|
+
#
|
172
|
+
def self.path( *args ) #:nodoc:
|
173
|
+
args.empty? ? PATH : ::File.join(PATH, *args)
|
174
|
+
end
|
175
|
+
|
176
|
+
# Utility method used to require all files ending in .rb that lie in the
|
177
|
+
# directory below this file that has the same name as the filename passed
|
178
|
+
# in. Optionally, a specific _directory_ name can be passed in such that
|
179
|
+
# the _filename_ does not have to be equivalent to the directory.
|
180
|
+
#
|
181
|
+
def self.require_all_libs_relative_to( fname, dir = nil ) #:nodoc:
|
182
|
+
dir ||= ::File.basename(fname, '.*')
|
183
|
+
search_me = ::File.expand_path( ::File.join(::File.dirname(fname), dir, '**', '*.rb'))
|
184
|
+
Dir.glob(search_me).sort.each {|rb| require rb}
|
185
|
+
end
|
186
|
+
|
187
|
+
# Utility method used to load all MOle config files ending in .rb that lie in the
|
188
|
+
# directory below this file that has the same name as the filename passed
|
189
|
+
# in. Optionally, a specific _directory_ name can be passed in such that
|
190
|
+
# the _filename_ does not have to be equivalent to the directory.
|
191
|
+
#
|
192
|
+
def self.load_all_moles_relative_to( mole_dir ) #:nodoc:
|
193
|
+
search_me = ::File.join( mole_dir, '**', '*.rb')
|
194
|
+
Dir.glob(search_me).sort.each {|rb| load rb}
|
195
|
+
end
|
196
|
+
|
197
|
+
# Stolen from inflector
|
198
|
+
def self.camelize(lower_case_and_underscored_word)
|
199
|
+
lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
|
200
|
+
end
|
201
|
+
|
202
|
+
# Fetch all ruby files in the given directory and return a cltn of class names
|
203
|
+
def self.find_controller_classes( dir )
|
204
|
+
classes = []
|
205
|
+
search_me = ::File.expand_path( ::File.join(dir, '*.rb'))
|
206
|
+
# BOZO !! This kind of sucks - need to exclude application controller for rails otherwise class loading error ??
|
207
|
+
Dir.glob(search_me).sort.each {|rb| classes << camelize( File.basename( rb, ".rb") ) unless File.basename( rb, ".rb") == "application" }
|
208
|
+
classes
|
209
|
+
end
|
210
|
+
|
211
|
+
# Automatically setup on perf MOle on any classes within a given directory
|
212
|
+
# NOTE: this call assumes the controller classes are in all in the path
|
213
|
+
def self.auto_perf( dir, &block )
|
214
|
+
controller_classes = find_controller_classes( dir )
|
215
|
+
controller_classes.each do |class_name|
|
216
|
+
clazz = Kernel.const_get( class_name )
|
217
|
+
features = ::Mole::Utils::Frameworks.features_for( clazz )
|
218
|
+
clazz.mole_perf( :features => features, &block )
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
# Automatically setup MOle untrapped exception on any classes within a given directory
|
223
|
+
# NOTE: this call assumes the controller classes are in all in the path
|
224
|
+
def self.auto_unchecked( dir, &block )
|
225
|
+
controller_classes = find_controller_classes( dir )
|
226
|
+
controller_classes.each do |class_name|
|
227
|
+
clazz = Kernel.const_get( class_name )
|
228
|
+
features = ::Mole::Utils::Frameworks.features_for( clazz )
|
229
|
+
clazz.mole_unchecked( :features => features, &block )
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
# Automatically setup MOle after filter on any classes within a given directory
|
234
|
+
# NOTE: this call assumes the controller classes are in all in the path
|
235
|
+
def self.auto_after( dir, &block )
|
236
|
+
controller_classes = find_controller_classes( dir )
|
237
|
+
controller_classes.each do |class_name|
|
238
|
+
clazz = Kernel.const_get( class_name )
|
239
|
+
features = ::Mole::Utils::Frameworks.features_for( clazz )
|
240
|
+
features.each do |feature|
|
241
|
+
clazz.mole_after( :feature => feature, &block )
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
# Automatically setup MOle after filter on any classes within a given directory
|
247
|
+
# NOTE: this call assumes the controller classes are in all in the path
|
248
|
+
def self.auto_before( dir, &block )
|
249
|
+
controller_classes = find_controller_classes( dir )
|
250
|
+
controller_classes.each do |class_name|
|
251
|
+
clazz = Kernel.const_get( class_name )
|
252
|
+
features = ::Mole::Utils::Frameworks.features_for( clazz )
|
253
|
+
features.each do |feature|
|
254
|
+
clazz.mole_before( :feature => feature, &block )
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
end
|
260
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# -----------------------------------------------------------------------------
|
4
|
+
# Sets up the MOle persistent layer
|
5
|
+
# Two tables are involved: mole_features and mole_logs
|
6
|
+
# -----------------------------------------------------------------------------
|
7
|
+
require 'rake'
|
8
|
+
require 'rake/tasklib'
|
9
|
+
|
10
|
+
module Mole
|
11
|
+
module Db
|
12
|
+
class Migrate
|
13
|
+
def initialize( opts )
|
14
|
+
@direction = opts.direction
|
15
|
+
@config = opts.configuration
|
16
|
+
@env = opts.environment
|
17
|
+
end
|
18
|
+
|
19
|
+
# Creates a MOle migration by creating or dropping the MOle related tables
|
20
|
+
def apply #:nodoc:
|
21
|
+
setup
|
22
|
+
@direction == :up ? migrate_up : migrate_down
|
23
|
+
end
|
24
|
+
|
25
|
+
# Setup database connection prior to applying migrations
|
26
|
+
def setup #:nodoc:
|
27
|
+
require 'rubygems'
|
28
|
+
gem "activerecord"
|
29
|
+
require 'active_record'
|
30
|
+
db_config = YAML.load_file( File.expand_path( @config ) )[@env]
|
31
|
+
::ActiveRecord::Base.establish_connection(db_config)
|
32
|
+
end
|
33
|
+
|
34
|
+
# ---------------------------------------------------------------------
|
35
|
+
# Create mole persistence tables ( 2 tables mole_features/mole_logs )
|
36
|
+
def migrate_up
|
37
|
+
# Create the mole_features table if it doesn't exist
|
38
|
+
unless ActiveRecord::Schema.tables.include?('mole_features')
|
39
|
+
ActiveRecord::Schema.create_table('mole_features') do |t|
|
40
|
+
t.column :name, :string
|
41
|
+
t.column :context, :string
|
42
|
+
t.column :app_name, :string
|
43
|
+
t.column :created_at, :datetime
|
44
|
+
t.column :updated_at, :datetime
|
45
|
+
end
|
46
|
+
ActiveRecord::Schema.add_index( 'mole_features',
|
47
|
+
['name', 'context', 'app_name'],
|
48
|
+
:name => 'feature_idx')
|
49
|
+
end
|
50
|
+
# Create the mole_logs table if it doesn't exist
|
51
|
+
unless ActiveRecord::Schema.tables.include?('mole_logs')
|
52
|
+
ActiveRecord::Schema.create_table('mole_logs') do |t|
|
53
|
+
t.column :mole_feature_id, :integer
|
54
|
+
t.column :user_id, :integer
|
55
|
+
t.column :params, :string, :limit => 1024
|
56
|
+
t.column :ip_address, :string
|
57
|
+
t.column :browser_type, :string
|
58
|
+
t.column :host_name, :string
|
59
|
+
t.column :created_at, :datetime
|
60
|
+
t.column :updated_at, :datetime
|
61
|
+
end
|
62
|
+
ActiveRecord::Schema.add_index( 'mole_logs',
|
63
|
+
['mole_feature_id','user_id'],
|
64
|
+
:name => "log_feature_idx" )
|
65
|
+
ActiveRecord::Schema.add_index( 'mole_logs',
|
66
|
+
['mole_feature_id','created_at'],
|
67
|
+
:name => "log_date_idx",
|
68
|
+
:unique => true )
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# -------------------------------------------------------------------------
|
73
|
+
# Destroys mole persistence tables
|
74
|
+
def migrate_down
|
75
|
+
# Delete the mole_feature table
|
76
|
+
if ActiveRecord::Schema.tables.include?( 'mole_features' )
|
77
|
+
ActiveRecord::Schema.remove_index( 'mole_features', :name => 'feature_idx' )
|
78
|
+
ActiveRecord::Schema.drop_table( 'mole_features' )
|
79
|
+
end
|
80
|
+
|
81
|
+
# Delete the mole_logs table
|
82
|
+
if ActiveRecord::Schema.tables.include?( 'mole_logs' )
|
83
|
+
ActiveRecord::Schema.remove_index( 'mole_logs', :name => 'log_feature_idx' )
|
84
|
+
ActiveRecord::Schema.remove_index( 'mole_logs', :name =>'log_date_idx' )
|
85
|
+
ActiveRecord::Schema.drop_table( 'mole_logs' )
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
data/lib/mole/e_mole.rb
ADDED
@@ -0,0 +1,75 @@
|
|
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
|