mole 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +4 -0
- data/Manifest.txt +45 -0
- data/README.txt +140 -0
- data/Rakefile +47 -0
- data/bin/mole +8 -0
- data/bin/molify +64 -0
- data/config/database.yml +21 -0
- data/config/test_database.yml +69 -0
- data/lib/mole/db/migrate.rb +90 -0
- data/lib/mole/e_mole.rb +74 -0
- data/lib/mole/logger.rb +131 -0
- data/lib/mole/models/mole_feature.rb +45 -0
- data/lib/mole/models/mole_log.rb +56 -0
- data/lib/mole/module.rb +274 -0
- data/lib/mole/moler.rb +51 -0
- data/lib/mole/utils/frameworks.rb +22 -0
- data/lib/mole/version.rb +15 -0
- data/lib/mole.rb +175 -0
- data/spec/data/blee.rb +53 -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 +37 -0
- data/spec/models/mole_log_spec.rb +73 -0
- data/spec/module_spec.rb +171 -0
- data/spec/mole_spec.rb +38 -0
- data/spec/moler_spec.rb +65 -0
- data/spec/spec_helper.rb +59 -0
- data/spec/utils/framework_spec.rb +46 -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
- data/test/test_mole.rb +0 -0
- metadata +120 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
History.txt
|
2
|
+
Manifest.txt
|
3
|
+
README.txt
|
4
|
+
Rakefile
|
5
|
+
bin/mole
|
6
|
+
bin/molify
|
7
|
+
config/database.yml
|
8
|
+
config/test_database.yml
|
9
|
+
lib/mole.rb
|
10
|
+
lib/mole/db/migrate.rb
|
11
|
+
lib/mole/e_mole.rb
|
12
|
+
lib/mole/logger.rb
|
13
|
+
lib/mole/models/mole_feature.rb
|
14
|
+
lib/mole/models/mole_log.rb
|
15
|
+
lib/mole/module.rb
|
16
|
+
lib/mole/moler.rb
|
17
|
+
lib/mole/utils/frameworks.rb
|
18
|
+
lib/mole/version.rb
|
19
|
+
spec/data/blee.rb
|
20
|
+
spec/db/migrate_spec.rb
|
21
|
+
spec/emole_spec.rb
|
22
|
+
spec/logger_spec.rb
|
23
|
+
spec/models/mole_feature_spec.rb
|
24
|
+
spec/models/mole_log_spec.rb
|
25
|
+
spec/module_spec.rb
|
26
|
+
spec/mole_spec.rb
|
27
|
+
spec/moler_spec.rb
|
28
|
+
spec/spec_helper.rb
|
29
|
+
spec/utils/framework_spec.rb
|
30
|
+
tasks/ann.rake
|
31
|
+
tasks/annotations.rake
|
32
|
+
tasks/doc.rake
|
33
|
+
tasks/gem.rake
|
34
|
+
tasks/manifest.rake
|
35
|
+
tasks/mole.rake
|
36
|
+
tasks/post_load.rake
|
37
|
+
tasks/rubyforge.rake
|
38
|
+
tasks/setup.rb
|
39
|
+
tasks/spec.rake
|
40
|
+
tasks/svn.rake
|
41
|
+
tasks/test.rake
|
42
|
+
templates/mole/e_mole/exception_alerts.rhtml
|
43
|
+
templates/mole/e_mole/feature_alerts.rhtml
|
44
|
+
templates/mole/e_mole/perf_alerts.rhtml
|
45
|
+
test/test_mole.rb
|
data/README.txt
ADDED
@@ -0,0 +1,140 @@
|
|
1
|
+
The MOle
|
2
|
+
by Fernand Galiana
|
3
|
+
liquidrail.com
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
The MOle allows you to track user's interactions with your ruby application and closely monitors
|
8
|
+
how your customers are using your application.
|
9
|
+
|
10
|
+
Whether you are releasing a new application or improving on an old one, it is always a good thing
|
11
|
+
to know if anyone is using your application and if they are, how they are using it.
|
12
|
+
What features are your users most fond of and which features find their way into the abyss?
|
13
|
+
Using the MOle you'll be able to rapidly assess whether or not your application is a hit and if
|
14
|
+
your coolest features are thought as such by your users. You will be able to elegantly record user
|
15
|
+
interactions and leverage these findings for the next iteration of your application.
|
16
|
+
|
17
|
+
== FEATURES:
|
18
|
+
|
19
|
+
The MOle allows you to easily
|
20
|
+
|
21
|
+
* Trap method calls within your ruby application. You can use the MOle with either a straight ruby
|
22
|
+
application, Rails or Merb. The MOle allows you to inject aspects across various method calls.
|
23
|
+
You are in full control on how and where to trap the calls and the arguments you want to record.
|
24
|
+
'Moled' methods are not limited to controller's actions, you can also mole any third party or library methods.
|
25
|
+
|
26
|
+
* Single configuration file. You won't have to sprinkle MOle code all over your application.
|
27
|
+
The MOle instructions reside in a single file easy to manage and maintain.
|
28
|
+
|
29
|
+
* Trap and surface uncaught exceptions in one easy call. The MOle will watch your execution stack
|
30
|
+
and alert you when an unexpected exception is encountered
|
31
|
+
|
32
|
+
* Trap and surface performance bottle neck in your ruby application in one easy call. You can
|
33
|
+
specify a performance threshold within the MOle configuration file. Any methods taking longer
|
34
|
+
than the specified threshold will trip an alert.
|
35
|
+
|
36
|
+
* You can record users interaction by either using the MOle is a transient or persistent mode.
|
37
|
+
In the persistent mode, users interactions will be recorded in your database. In the transient
|
38
|
+
case, MOle events will be recorded in your application logs.
|
39
|
+
|
40
|
+
== INSTALL:
|
41
|
+
|
42
|
+
* sudo gem install mole
|
43
|
+
|
44
|
+
== SYNOPSIS:
|
45
|
+
|
46
|
+
* Mole initialization. This must be specified during your application initialization code.
|
47
|
+
In a rails app, this can be set in you application controller class or environment.rb. In
|
48
|
+
a Merb app, this can be set in your merb_init.rb file.
|
49
|
+
|
50
|
+
require 'mole'
|
51
|
+
Mole.initialize( :moleable => true,
|
52
|
+
:emole_from => "MoleBeatch@acme.com",
|
53
|
+
:emole_recipients => ['fernand@acme.com'],
|
54
|
+
:mode => :persistent,
|
55
|
+
:log_file => $stdout,
|
56
|
+
:log_level => :debug,
|
57
|
+
:perf_threshold => 2,
|
58
|
+
:application => "Smf",
|
59
|
+
:mole_config => File.join( File.dirname(__FILE__), %w[mole.rb] ) )
|
60
|
+
|
61
|
+
* Now you'll need to create a mole.rb specification file to specify the various aspects you'll want
|
62
|
+
to inject. This file is specified in the initialize call via the :mole_config tag.
|
63
|
+
|
64
|
+
To trap a feature before or after it occurs you can use the mole_before/mole_after
|
65
|
+
interceptors. The following will mole the "Posts" class after the "show" method is called.
|
66
|
+
The context argument hands you an execution context. In a rails/merb environment
|
67
|
+
this will be your controller object. You can handle this interaction any way
|
68
|
+
you want. The MOle provides a convenience class to record this interaction via
|
69
|
+
the database or the MOle logger in the guise of Mole::Moler. But you can also log it to
|
70
|
+
any media you'll find suitable. In a rails/merb context, you'll be able to extract session/params information
|
71
|
+
as in this case.
|
72
|
+
|
73
|
+
Posts.mole_after( :feature => :show ) { |context, feature, ret, args, block|
|
74
|
+
# Records the interaction to the database
|
75
|
+
Mole::Moler.mole_it( context, feature,
|
76
|
+
context.session[:user_id], # Retrieves which user performed this action
|
77
|
+
:post_id=> context.params[:post_id], # Records request parameter post id
|
78
|
+
:url => context.instance_variable_get( "@url" ) ) # Retrieves controller state
|
79
|
+
end
|
80
|
+
}
|
81
|
+
|
82
|
+
To record performance issues, you will need to provide a collection of
|
83
|
+
methods that must be watched on a given class. In the case of rails or merb you can easily fetch the list
|
84
|
+
of actions from the controller api and pass it to the MOle. The MOle provides convenience
|
85
|
+
classes to log the perf issues to your database and send out alerts when a perf condition is met.
|
86
|
+
Upon invocation, you will be handed a calling context, that comprises the feature (method) being
|
87
|
+
called, the actual time it took to complete the call and any args/block that was passed into
|
88
|
+
the feature that causes the performance threshold to be triggered. Setting the :email option
|
89
|
+
to true will also send out an email alert.
|
90
|
+
|
91
|
+
Posts.mole_perf( :features => merb_actions ) do |context, feature, elapsed_time, args, block|
|
92
|
+
user = context.instance_variable_get( "@user" )
|
93
|
+
key = context.params[:key], "N/A"
|
94
|
+
request = context.request.nil? ? "N/A" : context.request.remote_ip,
|
95
|
+
Mole::Moler.perf_it( context, user.id,
|
96
|
+
:controller => context.class.name,
|
97
|
+
:feature => feature,
|
98
|
+
:key => key,
|
99
|
+
:request => request,
|
100
|
+
:user => user.user_name,
|
101
|
+
:elapsed_time => "%3.3f" % elapsed_time,
|
102
|
+
:email => true )
|
103
|
+
end
|
104
|
+
|
105
|
+
The unchecked exception trap works very similarly to the mole_perf trap. It will pass in
|
106
|
+
the context of the method that triggered the exception.
|
107
|
+
|
108
|
+
Posts.mole_unchecked( :features => merb_actions ) do |context, action, boom, args, block|
|
109
|
+
sub = context.instance_variable_get("@sub")
|
110
|
+
user_id = "N/A"
|
111
|
+
user_id = sub.user.id if sub and sub.user
|
112
|
+
Mole::Moler.check_it( context, user_id,
|
113
|
+
:controller => context.class.name,
|
114
|
+
:action => action,
|
115
|
+
:boom => boom,
|
116
|
+
:email => true )
|
117
|
+
end
|
118
|
+
|
119
|
+
== LICENSE:
|
120
|
+
|
121
|
+
MIT Copyright (c) 2008
|
122
|
+
|
123
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
124
|
+
a copy of this software and associated documentation files (the
|
125
|
+
'Software'), to deal in the Software without restriction, including
|
126
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
127
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
128
|
+
permit persons to whom the Software is furnished to do so, subject to
|
129
|
+
the following conditions:
|
130
|
+
|
131
|
+
The above copyright notice and this permission notice shall be
|
132
|
+
included in all copies or substantial portions of the Software.
|
133
|
+
|
134
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
135
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
136
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
137
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
138
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
139
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
140
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# Look in the tasks/setup.rb file for the various options that can be
|
2
|
+
# configured in this Rakefile. The .rake files in the tasks directory
|
3
|
+
# are where the options are used.
|
4
|
+
|
5
|
+
load 'tasks/setup.rb'
|
6
|
+
|
7
|
+
ensure_in_path 'lib'
|
8
|
+
require 'mole'
|
9
|
+
require 'mole/version'
|
10
|
+
|
11
|
+
task :default => 'spec:run'
|
12
|
+
|
13
|
+
PROJ.name = 'mole'
|
14
|
+
PROJ.authors = 'Fernand Galiana'
|
15
|
+
PROJ.email = 'fernand@liquidrail.com'
|
16
|
+
PROJ.url = 'http://mole.rubyforge.org'
|
17
|
+
PROJ.rubyforge_name = 'mole'
|
18
|
+
PROJ.description = "A flexible way to track user's interactions within your ruby web applications"
|
19
|
+
PROJ.spec_opts << '--color'
|
20
|
+
PROJ.rcov_dir = ENV['CC_BUILD_ARTIFACTS'] ? "#{ENV['CC_BUILD_ARTIFACTS']}/test_coverage" : 'coverage'
|
21
|
+
PROJ.rdoc_dir = ENV['CC_BUILD_ARTIFACTS'] ? "#{ENV['CC_BUILD_ARTIFACTS']}/api_docs" : 'docs'
|
22
|
+
PROJ.ruby_opts = %w[-W0]
|
23
|
+
PROJ.version = ::Mole::Version.version
|
24
|
+
PROJ.svn = 'mole'
|
25
|
+
PROJ.rcov_threshold = 90.0
|
26
|
+
PROJ.executables = ['molify']
|
27
|
+
|
28
|
+
PROJ.exclude << %w[.DS_Store$ .swo$ .swp$]
|
29
|
+
PROJ.tests = FileList['test/**/test_*.rb']
|
30
|
+
PROJ.dependencies = [ ["logging"] ]
|
31
|
+
PROJ.annotation_tags << 'BOZO'
|
32
|
+
|
33
|
+
desc "Clean up artifact directories"
|
34
|
+
task :clean do
|
35
|
+
rcov_artifacts = File.join( File.dirname( __FILE__ ), "coverage" )
|
36
|
+
FileUtils.rm_rf rcov_artifacts if File.exists? rcov_artifacts
|
37
|
+
rdoc_artifacts = File.join( File.dirname( __FILE__ ), "docs" )
|
38
|
+
FileUtils.rm_rf rdoc_artifacts if File.exists? rdoc_artifacts
|
39
|
+
gem_artifacts = File.join( File.dirname( __FILE__ ), "pkg" )
|
40
|
+
FileUtils.rm_rf gem_artifacts if File.exists? gem_artifacts
|
41
|
+
end
|
42
|
+
|
43
|
+
task 'gem:package' => 'manifest:assert'
|
44
|
+
|
45
|
+
|
46
|
+
depend_on "logging" , "= 0.7.0"
|
47
|
+
depend_on "activerecord", "= 2.0.2"
|
data/bin/mole
ADDED
data/bin/molify
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'optparse'
|
3
|
+
|
4
|
+
require File.expand_path(
|
5
|
+
File.join(File.dirname(__FILE__), '..', 'lib', 'mole') )
|
6
|
+
|
7
|
+
require 'mole/db/migrate'
|
8
|
+
|
9
|
+
module Mole
|
10
|
+
class Molify
|
11
|
+
# Performs db migration when the MOle is to be used in a persistent mode.
|
12
|
+
def initialize( argv=ARGV )
|
13
|
+
option_parser = default_option_parser
|
14
|
+
option_parser.parse!(argv)
|
15
|
+
puts options.inspect
|
16
|
+
::Mole::Db::Migrate.new( options ).apply
|
17
|
+
end
|
18
|
+
|
19
|
+
# access the options
|
20
|
+
def options #:nodoc:
|
21
|
+
if not @options then
|
22
|
+
@options = OpenStruct.new
|
23
|
+
# Unless specified attempt to lookup config/database.yml
|
24
|
+
@options.configuration = File.join( Dir.pwd, %w[config database.yml] )
|
25
|
+
# Unless specified assumes test env
|
26
|
+
@options.environment = "test"
|
27
|
+
# Unless specficied migrates up
|
28
|
+
@options.direction = :up
|
29
|
+
end
|
30
|
+
return @options
|
31
|
+
end
|
32
|
+
|
33
|
+
def default_option_parser #:nodoc:
|
34
|
+
OptionParser.new do |op|
|
35
|
+
op.separator ""
|
36
|
+
op.separator "Molify options"
|
37
|
+
|
38
|
+
op.on( "-c", "--config FILE", "The location of the database configuration file." ) do |db|
|
39
|
+
options.configuration = db
|
40
|
+
end
|
41
|
+
|
42
|
+
op.on("-e", "--env ENV", "The environment to run in." ) do |env|
|
43
|
+
options.environment = env
|
44
|
+
end
|
45
|
+
|
46
|
+
op.on("-u", "--up", "Install MOle related tables") do |dir|
|
47
|
+
options.direction= :up
|
48
|
+
end
|
49
|
+
|
50
|
+
op.on("-d", "--down", "Uninstall MOle related tables") do |dir|
|
51
|
+
options.direction= :down
|
52
|
+
end
|
53
|
+
|
54
|
+
op.separator ""
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
Mole::Molify.new(ARGV)
|
61
|
+
|
62
|
+
|
63
|
+
|
64
|
+
|
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
|
@@ -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,74 @@
|
|
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
|
+
buff = boom.backtrace[0...3].join( "\r" )
|
60
|
+
end
|
61
|
+
|
62
|
+
# dumps arguments
|
63
|
+
def dump_args( args )
|
64
|
+
return "N/A" unless args
|
65
|
+
buff = []
|
66
|
+
args.keys.sort { |a,b| a.to_s <=> b.to_s}.each do |k|
|
67
|
+
key = k.to_s.rjust(20)
|
68
|
+
value = args[k].to_s.rjust(97,".")
|
69
|
+
buff << "#{key} : #{value}"
|
70
|
+
end
|
71
|
+
buff.join( "\r" )
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|