mole 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|