rackamole 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY +8 -0
- data/README.rdoc +20 -5
- data/lib/rackamole.rb +1 -1
- data/lib/rackamole/mole.rb +1 -1
- data/lib/rackamole/store/mongo_db.rb +37 -9
- data/samples/sinatra/moled.rb +13 -9
- data/spec/rackamole/alert/emole_spec.rb +4 -4
- data/spec/rackamole/store/mongo_db_spec.rb +19 -7
- metadata +3 -2
data/HISTORY
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
0.0.1 - 0.1.0
|
2
|
+
* Initial drop and bug fixes. Not that interesting...
|
3
|
+
|
4
|
+
0.1.1
|
5
|
+
* Updated mongo store strategy
|
6
|
+
* Tossed out mongo mapper. Trying to stay closer to the metal
|
7
|
+
* Shortened col names for saving space. Unfortunately lame but necessary
|
8
|
+
* Moved user info into separate collection.
|
data/README.rdoc
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
== RackAMole
|
2
|
-
|
2
|
+
Observe your web applications in the wild!
|
3
3
|
|
4
4
|
== DESCRIPTION:
|
5
5
|
|
@@ -27,7 +27,7 @@ interactions and leverage these findings for the next iteration of your applicat
|
|
27
27
|
|
28
28
|
== FEATURES:
|
29
29
|
|
30
|
-
* Monitors Rails
|
30
|
+
* Monitors any rack based framework such as Rails and Sinatra
|
31
31
|
* Captures the essence of the request as well as user information
|
32
32
|
* Tracks performance issues based on your latency threshold
|
33
33
|
* Tracks exceptions that might occurred during a request
|
@@ -36,14 +36,13 @@ interactions and leverage these findings for the next iteration of your applicat
|
|
36
36
|
|
37
37
|
* Logging
|
38
38
|
* Hitimes
|
39
|
-
* MongoDb
|
39
|
+
* MongoDb + mongo ruby adapter
|
40
40
|
|
41
41
|
== INSTALL:
|
42
42
|
|
43
43
|
* sudo gem install rackamole
|
44
44
|
|
45
|
-
NOTE: The gem is hosted on gemcutter.
|
46
|
-
already specified
|
45
|
+
NOTE: The gem is hosted on gemcutter.org
|
47
46
|
|
48
47
|
== USAGE:
|
49
48
|
|
@@ -78,6 +77,22 @@ interactions and leverage these findings for the next iteration of your applicat
|
|
78
77
|
This assumes that you have session enabled to identify a user if not the mole will log the user
|
79
78
|
as 'Unknown'
|
80
79
|
|
80
|
+
=== Storing moled information
|
81
|
+
|
82
|
+
Rackamole currently comes with a single storage strategy. More will come in the near future, but
|
83
|
+
currently we are using MongoDb as our default storage. The idea here is to create a database for
|
84
|
+
a given moled app per environment. For instance, for application 'Fred', you will need to use a
|
85
|
+
separate store for Fred running in alpha mode and Fred running in production mode.
|
86
|
+
|
87
|
+
In order to use a store, you will need to pass in the :store option. There currently 2 store
|
88
|
+
types a logger and a mongo adapter. By default the store is set to log moled information to the console.
|
89
|
+
To change to a mongo store simply add the following options:
|
90
|
+
|
91
|
+
use Rack::Mole, { :app_name => "Fred", :store => Rackamole::Store::MongoDb.new( :database => 'mole_fred_alpha_mdb' ) }
|
92
|
+
|
93
|
+
This expect a local mongo instance to be running on the default port. You can change the
|
94
|
+
location by adding :host and :port options.
|
95
|
+
|
81
96
|
== LICENSE:
|
82
97
|
|
83
98
|
(The MIT License)
|
data/lib/rackamole.rb
CHANGED
data/lib/rackamole/mole.rb
CHANGED
@@ -22,7 +22,7 @@ module Rack
|
|
22
22
|
# :perf_threshold :: Any request taking longer than this value will get moled. Default: 10secs
|
23
23
|
# :moleable :: Enable/Disable the MOle (Default:true)
|
24
24
|
# :store :: The storage instance ie log file or mongodb [Default:stdout]
|
25
|
-
# :expiration :: Number of seconds to expiration. The mole will not keep sending alert if a particular
|
25
|
+
# :expiration :: Number of seconds to alert expiration. The mole will not keep sending alert if a particular
|
26
26
|
# mole type has been reported in the past. This threshold specifies the limit at which
|
27
27
|
# the previously sent alerts will expire and thus will be sent again.
|
28
28
|
# For instance, it might be the case that the app is consistently slow for a particular action.
|
@@ -7,7 +7,7 @@ module Rackamole
|
|
7
7
|
# Mongo adapter. Stores mole info to a mongo database.
|
8
8
|
class MongoDb
|
9
9
|
|
10
|
-
attr_reader :database, :logs, :features #:nodoc:
|
10
|
+
attr_reader :database, :logs, :features, :users #:nodoc:
|
11
11
|
|
12
12
|
# Initializes the mongo db store. MongoDb can be used as a persitent store for
|
13
13
|
# mole information. This is a preferred store for the mole as it will allow you
|
@@ -41,7 +41,7 @@ module Rackamole
|
|
41
41
|
args = arguments.clone
|
42
42
|
|
43
43
|
# dump request info to mongo
|
44
|
-
save_log( save_feature( args ), args )
|
44
|
+
save_log( save_user( args ), save_feature( args ), args )
|
45
45
|
rescue => mole_boom
|
46
46
|
$stderr.puts "MOLE STORE CRAPPED OUT -- #{mole_boom}"
|
47
47
|
$stderr.puts mole_boom.backtrace.join( "\n " )
|
@@ -54,6 +54,7 @@ module Rackamole
|
|
54
54
|
def reset!
|
55
55
|
logs.remove
|
56
56
|
features.remove
|
57
|
+
users.remove
|
57
58
|
end
|
58
59
|
|
59
60
|
def init_mongo( opts )
|
@@ -61,6 +62,7 @@ module Rackamole
|
|
61
62
|
@database = @connection.db( opts[:database] )
|
62
63
|
@features = database.collection( 'features' )
|
63
64
|
@logs = database.collection( 'logs' )
|
65
|
+
@users = database.collection( 'users' )
|
64
66
|
end
|
65
67
|
|
66
68
|
# Validates option hash.
|
@@ -77,12 +79,34 @@ module Rackamole
|
|
77
79
|
def default_options
|
78
80
|
{
|
79
81
|
:host => 'localhost',
|
80
|
-
:port =>
|
82
|
+
:port => Mongo::Connection::DEFAULT_PORT,
|
81
83
|
:database => 'mole_mdb'
|
82
84
|
}
|
83
85
|
end
|
84
86
|
|
85
|
-
# Find or create a
|
87
|
+
# Find or create a moled user...
|
88
|
+
# BOZO !! What to do if user name changed ?
|
89
|
+
def save_user( args )
|
90
|
+
user_id = args.delete( :user_id ) if args.has_key?( :user_id )
|
91
|
+
user_name = args.delete( :user_name ) if args.has_key?( :user_name )
|
92
|
+
|
93
|
+
row = {}
|
94
|
+
if user_id and user_name
|
95
|
+
row = { min_field( :user_id ) => user_id, min_field( :user_name ) => user_name }
|
96
|
+
else
|
97
|
+
row = { min_field( :user_name ) => user_name }
|
98
|
+
end
|
99
|
+
|
100
|
+
user = users.find_one( row, :fields => ['_id'] )
|
101
|
+
return user['_id'] if user
|
102
|
+
|
103
|
+
now = args[:created_at]
|
104
|
+
row[min_field(:date_id)] = "%4d%02d%02d" % [now.year, now.month, now.day]
|
105
|
+
|
106
|
+
users.save( row )
|
107
|
+
end
|
108
|
+
|
109
|
+
# Find or create a mole feature...
|
86
110
|
def save_feature( args )
|
87
111
|
app_name = args.delete( :app_name )
|
88
112
|
route_info = args.delete( :route_info )
|
@@ -99,7 +123,8 @@ module Rackamole
|
|
99
123
|
feature = features.find_one( row, :fields => ['_id'] )
|
100
124
|
return feature['_id'] if feature
|
101
125
|
|
102
|
-
|
126
|
+
now = args[:created_at]
|
127
|
+
row[min_field(:date_id)] = "%4d%02d%02d" %[now.year, now.month, now.day]
|
103
128
|
|
104
129
|
features.save( row )
|
105
130
|
end
|
@@ -107,13 +132,16 @@ module Rackamole
|
|
107
132
|
# Insert a new feature in the db
|
108
133
|
# NOTE : Using min key to reduce storage needs. I know not that great for higher level api's :-(
|
109
134
|
# also saving date and time as ints. same deal...
|
110
|
-
def save_log( feature_id, args )
|
135
|
+
def save_log( user_id, feature_id, args )
|
136
|
+
puts "Saving LOG for #{feature_id} -- #{user_id}"
|
137
|
+
puts caller.inspect
|
111
138
|
now = args.delete( :created_at )
|
112
139
|
row = {
|
113
140
|
min_field( :type ) => args[:type],
|
114
|
-
min_field( :feature_id ) => feature_id
|
115
|
-
min_field( :
|
116
|
-
min_field( :
|
141
|
+
min_field( :feature_id ) => feature_id,
|
142
|
+
min_field( :user_id ) => user_id,
|
143
|
+
min_field( :date_id ) => "%4d%02d%02d" %[now.year, now.month, now.day],
|
144
|
+
min_field( :time_id ) => "%02d%02d%02d" %[now.hour, now.min, now.sec]
|
117
145
|
}
|
118
146
|
|
119
147
|
args.each do |k,v|
|
data/samples/sinatra/moled.rb
CHANGED
@@ -2,20 +2,25 @@ require 'rubygems'
|
|
2
2
|
require 'sinatra'
|
3
3
|
require 'rackamole'
|
4
4
|
|
5
|
-
set :environment, :production
|
6
5
|
|
7
|
-
configure
|
8
|
-
set :sessions,
|
6
|
+
configure do
|
7
|
+
set :sessions, true
|
8
|
+
|
9
|
+
puts "mole_sinatra_#{Sinatra::Application.environment}_mdb"
|
10
|
+
|
9
11
|
use Rack::Lint
|
10
12
|
use Rack::Session::Cookie
|
11
13
|
use Rack::Mole, {
|
12
|
-
:app_name => "Moled Franky",
|
14
|
+
:app_name => "Moled Franky",
|
15
|
+
:environment => Sinatra::Application.environment,
|
13
16
|
:log_level => :debug,
|
14
17
|
:user_key => :user_name,
|
18
|
+
# :store => Rackamole::Store::MongoDb.new( :database => "mole_sinatra_dev_mdb" ),
|
19
|
+
:store => Rackamole::Store::MongoDb.new( :database => "mole_sinatra_#{Sinatra::Application.environment}_mdb" ),
|
15
20
|
:expiration => 10,
|
16
21
|
:perf_threshold => 0.2,
|
17
22
|
:twitter => { :username => 'moled', :password => 'fernand~1', :alert_on => [Rackamole.perf, Rackamole.fault] },
|
18
|
-
:excluded_paths => [ /.+?\.css/, /.+?\.png/ ]
|
23
|
+
:excluded_paths => [ /.+?\.css/, /.+?\.js/, /.+?\.png/ ]
|
19
24
|
}
|
20
25
|
end
|
21
26
|
|
@@ -24,25 +29,24 @@ before do
|
|
24
29
|
end
|
25
30
|
|
26
31
|
get '/' do
|
27
|
-
puts "Yo"
|
28
32
|
erb :index
|
29
33
|
end
|
30
34
|
|
31
35
|
get '/normal' do
|
32
36
|
@blee = "Hello World!"
|
33
|
-
session[:
|
34
|
-
|
37
|
+
session[:normal] = "something normal"
|
35
38
|
erb :normal
|
36
39
|
end
|
37
40
|
|
38
41
|
post '/post' do
|
39
42
|
@post = params[:blee]
|
43
|
+
session[:post] = "something posted"
|
40
44
|
erb :post
|
41
45
|
end
|
42
46
|
|
43
47
|
get '/params/:id' do
|
44
48
|
@blee = params[:id]
|
45
|
-
session[:
|
49
|
+
session[:param] = "something param"
|
46
50
|
|
47
51
|
erb :params
|
48
52
|
end
|
@@ -23,8 +23,8 @@ describe Rackamole::Alert::Emole do
|
|
23
23
|
|
24
24
|
it "should send a feature email correctly" do
|
25
25
|
@expected.subject = "[M()le] (Feature) -Test@Fred- for user Fernand"
|
26
|
-
@expected.body = feature_body
|
27
|
-
Rackamole::Alert::Emole.create_alert( @from, @to, @args ).
|
26
|
+
@expected.body = feature_body
|
27
|
+
Rackamole::Alert::Emole.create_alert( @from, @to, @args ).body_port.to_s.should == @expected.body_port.to_s
|
28
28
|
end
|
29
29
|
|
30
30
|
it "should send a perf email correctly" do
|
@@ -32,7 +32,7 @@ describe Rackamole::Alert::Emole do
|
|
32
32
|
@args[:request_time] = 10.0
|
33
33
|
@expected.subject = "[M()le] (Performance:10.0) -Test@Fred- for user Fernand"
|
34
34
|
@expected.body = perf_body
|
35
|
-
Rackamole::Alert::Emole.create_alert( @from, @to, @args ).
|
35
|
+
Rackamole::Alert::Emole.create_alert( @from, @to, @args ).body_port.to_s.should == @expected.body_port.to_s
|
36
36
|
end
|
37
37
|
|
38
38
|
it "should send a fault email correctly" do
|
@@ -42,7 +42,7 @@ describe Rackamole::Alert::Emole do
|
|
42
42
|
@args[:params] = { :id => 10 }
|
43
43
|
@expected.subject = "[M()le] (Fault) -Test@Fred- for user Fernand"
|
44
44
|
@expected.body = fault_body
|
45
|
-
Rackamole::Alert::Emole.create_alert( @from, @to, @args ).
|
45
|
+
Rackamole::Alert::Emole.create_alert( @from, @to, @args ).body_port.to_s.should == @expected.body_port.to_s
|
46
46
|
end
|
47
47
|
|
48
48
|
end
|
@@ -1,9 +1,11 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), %w[.. .. spec_helper])
|
2
|
+
require 'chronic'
|
2
3
|
|
3
4
|
describe Rackamole::Store::MongoDb do
|
4
5
|
|
5
6
|
describe "#mole" do
|
6
7
|
before( :all ) do
|
8
|
+
@now = Chronic.parse( "11/27/2009" )
|
7
9
|
@store = Rackamole::Store::MongoDb.new(
|
8
10
|
:host => 'localhost',
|
9
11
|
:port => 27017,
|
@@ -30,7 +32,7 @@ describe Rackamole::Store::MongoDb do
|
|
30
32
|
@args[:method] = 'GET'
|
31
33
|
@args[:params] = { :blee => "duh".to_json }
|
32
34
|
@args[:session] = { :fred => 10.to_json }
|
33
|
-
@args[:created_at] =
|
35
|
+
@args[:created_at] = @now.utc
|
34
36
|
end
|
35
37
|
|
36
38
|
it "should mole a context based feature correctly" do
|
@@ -46,7 +48,7 @@ describe Rackamole::Store::MongoDb do
|
|
46
48
|
|
47
49
|
log = @store.logs.find_one()
|
48
50
|
log.should_not be_nil
|
49
|
-
log['typ'].should
|
51
|
+
log['typ'].should == Rackamole.feature
|
50
52
|
log['fid'].should_not be_nil
|
51
53
|
log['par'].should == { 'blee' => 'duh'.to_json }
|
52
54
|
log['ip'].should == '1.1.1.1'
|
@@ -54,13 +56,23 @@ describe Rackamole::Store::MongoDb do
|
|
54
56
|
log['url'].should == 'http://test_me/'
|
55
57
|
log['met'].should == 'GET'
|
56
58
|
log['ses'].should == { 'fred' => '10' }
|
57
|
-
log['
|
58
|
-
log['uid'].should == 100
|
59
|
+
log['uid'].should_not be_nil
|
59
60
|
log['rti'].should == 1.0
|
60
|
-
log['did'].
|
61
|
-
log['tid'].
|
61
|
+
log['did'].should == '20091127'
|
62
|
+
log['tid'].should == '190000'
|
62
63
|
|
63
|
-
@store.features.find_one(
|
64
|
+
feature = @store.features.find_one( log['fid'] )
|
65
|
+
feature.should_not be_nil
|
66
|
+
feature['app'].should == 'Test app'
|
67
|
+
feature['env'].should == 'test'
|
68
|
+
feature['ctx'].should == '/fred'
|
69
|
+
feature['did'].should == '20091127'
|
70
|
+
|
71
|
+
user = @store.users.find_one( log['uid'] )
|
72
|
+
user.should_not be_nil
|
73
|
+
user['una'].should == "Fernand"
|
74
|
+
user['uid'].should == 100
|
75
|
+
user['did'].should == '20091127'
|
64
76
|
end
|
65
77
|
|
66
78
|
it "should mole a rails feature correctly" do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rackamole
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Fernand Galiana
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-12-09 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -105,6 +105,7 @@ extra_rdoc_files:
|
|
105
105
|
- samples/rails/moled/public/robots.txt
|
106
106
|
files:
|
107
107
|
- ...
|
108
|
+
- HISTORY
|
108
109
|
- README.rdoc
|
109
110
|
- Rakefile
|
110
111
|
- aaa.txt
|