rackamole 0.0.4 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -19,9 +19,9 @@ interactions and leverage these findings for the next iteration of your applicat
19
19
  == PROJECT INFORMATION
20
20
 
21
21
  * Developer: Fernand Galiana
22
- * Blog: liquidrail.com
23
- * Site: rackamole.com
24
- * Twitter: @rackamole
22
+ * Blog: http://www.liquidrail.com
23
+ * Site: http://rackamole.com
24
+ * Twitter: https://twitter.com/rackamole
25
25
  * Forum: http://groups.google.com/group/rackamole
26
26
  * Git: git://github.com/derailed/rackamole.git
27
27
 
data/Rakefile CHANGED
@@ -19,10 +19,13 @@ PROJ.authors = 'Fernand Galiana'
19
19
  PROJ.email = 'fernand.galiana@gmail.com'
20
20
  PROJ.url = 'http://rackamole.liquidrail.com'
21
21
  PROJ.version = Rackamole::VERSION
22
- PROJ.spec.opts << '--color'
22
+ PROJ.spec.opts << '--color'
23
23
  PROJ.ruby_opts = %w[-W0]
24
+ PROJ.readme = 'README.rdoc'
25
+ PROJ.rcov.opts = ["--sort", "coverage", "-T", '-x mongo']
24
26
 
25
27
  # Dependencies
26
28
  depend_on "logging" , ">= 1.2.2"
27
29
  depend_on "hitimes" , ">= 1.0.3"
28
- depend_on "mongodb-mongo", ">= 0.14.1"
30
+ depend_on "mongo" , ">= 0.17.1"
31
+ depend_on "darkfish-rdoc", ">= 1.1.5"
@@ -1,6 +1,6 @@
1
1
  require 'hitimes'
2
- require 'mongo/util/ordered_hash'
3
2
  require 'json'
3
+ require 'mongo'
4
4
 
5
5
  module Rack
6
6
  class Mole
@@ -81,33 +81,33 @@ module Rack
81
81
  session = env['rack.session']
82
82
  route = get_route( request )
83
83
 
84
- ip, browser = identify( env )
85
- user_id = nil
86
- user_name = nil
84
+ ip, user_agent = identify( env )
85
+ user_id = nil
86
+ user_name = nil
87
87
 
88
88
  # BOZO !! This could be slow if have to query db to get user name...
89
89
  # Preferred store username in session and give at key
90
90
  if session and @user_key
91
- if @user_key.instance_of? Symbol
92
- user_name = session[@user_key]
93
- elsif @user_key.instance_of? Hash
91
+ if @user_key.instance_of? Hash
94
92
  user_id = session[ @user_key[:session_key] ]
95
93
  if @user_key[:extractor]
96
94
  user_name = @user_key[:extractor].call( user_id )
97
95
  end
96
+ else
97
+ user_name = session[@user_key]
98
98
  end
99
99
  end
100
100
 
101
101
  info[:app_name] = @app_name
102
- info[:environment] = @environment if @environment
102
+ info[:environment] = @environment || "Unknown"
103
103
  info[:user_id] = user_id if user_id
104
104
  info[:user_name] = user_name || "Unknown"
105
105
  info[:ip] = ip
106
- info[:browser] = browser
106
+ info[:browser] = id_browser( user_agent )
107
107
  info[:host] = env['SERVER_NAME']
108
108
  info[:software] = env['SERVER_SOFTWARE']
109
109
  info[:request_time] = elapsed if elapsed
110
- info[:perf_issue] = (elapsed and elapsed > @perf_threshold)
110
+ info[:performance] = (elapsed and elapsed > @perf_threshold)
111
111
  info[:url] = request.url
112
112
  info[:method] = env['REQUEST_METHOD']
113
113
  info[:path] = request.path
@@ -138,6 +138,18 @@ module Rack
138
138
  boom.backtrace.each { |l| $stderr.puts l }
139
139
  end
140
140
 
141
+ # Attempts to detect browser type from agent info.
142
+ # BOZO !! Probably more efficient way to do this...
143
+ def browser_types() @browsers ||= [ 'Firefox', 'Safari', 'MSIE 8.0', 'MSIE 7.0', 'MSIE 6.0', 'Opera', 'Chrome' ] end
144
+
145
+ def id_browser( user_agent )
146
+ return "N/A" if !user_agent or user_agent.empty?
147
+ browser_types.each do |b|
148
+ return b if user_agent.match( /.*?#{b.gsub(/\./,'\.')}.*?/ )
149
+ end
150
+ "N/A"
151
+ end
152
+
141
153
  # Trim stack trace
142
154
  def trim_stack( boom )
143
155
  boom.backtrace[0...4]
@@ -155,23 +167,29 @@ module Rack
155
167
 
156
168
  # Fetch route info if any...
157
169
  def get_route( request )
158
- return nil unless defined?( RAILS_ENV )
159
- ::ActionController::Routing::Routes.recognize_path( request.path, {:method => request.request_method.downcase.to_sym } )
170
+ return nil unless defined?( RAILS_ENV )
171
+
172
+ # Check for invalid route exception...
173
+ begin
174
+ return ::ActionController::Routing::Routes.recognize_path( request.path, {:method => request.request_method.downcase.to_sym } )
175
+ rescue
176
+ return nil
177
+ end
160
178
  end
161
179
 
162
180
  # Dump env to stdout
163
- def dump( env, level=0 )
164
- env.keys.sort{ |a,b| a.to_s <=> b.to_s }.each do |k|
165
- value = env[k]
166
- if value.respond_to?(:each_pair)
167
- puts "%s %-#{40-level}s" % [' '*level,k]
168
- dump( env[k], level+1 )
169
- elsif value.instance_of?(::ActionController::Request) or value.instance_of?(::ActionController::Response)
170
- puts "%s %-#{40-level}s %s" % [ ' '*level, k, value.class ]
171
- else
172
- puts "%s %-#{40-level}s %s" % [ ' '*level, k, value.inspect ]
173
- end
174
- end
175
- end
181
+ # def dump( env, level=0 )
182
+ # env.keys.sort{ |a,b| a.to_s <=> b.to_s }.each do |k|
183
+ # value = env[k]
184
+ # if value.respond_to?(:each_pair)
185
+ # puts "%s %-#{40-level}s" % [' '*level,k]
186
+ # dump( env[k], level+1 )
187
+ # elsif value.instance_of?(::ActionController::Request) or value.instance_of?(::ActionController::Response)
188
+ # puts "%s %-#{40-level}s %s" % [ ' '*level, k, value.class ]
189
+ # else
190
+ # puts "%s %-#{40-level}s %s" % [ ' '*level, k, value.inspect ]
191
+ # end
192
+ # end
193
+ # end
176
194
  end
177
195
  end
@@ -0,0 +1,139 @@
1
+ require 'mongo'
2
+
3
+ # TODO !! Need to deal with auth
4
+ # BOZO !! Deal with indexes here ?
5
+ module Rackamole
6
+ module Store
7
+ # Mongo adapter. Stores mole info in a mongo database.
8
+ class MongoDb
9
+
10
+ attr_reader :database, :logs, :features
11
+
12
+ # Defines the various feature types
13
+ FEATURE = 0
14
+ PERFORMANCE = 1
15
+ EXCEPTION = 2
16
+
17
+ def initialize( options={} )
18
+ opts = default_options.merge( options )
19
+ init_mongo( opts )
20
+ end
21
+
22
+ # clear out db content ( used in testing... )
23
+ def reset!
24
+ logs.remove
25
+ features.remove
26
+ end
27
+
28
+ # Dump mole info to logger
29
+ def mole( arguments )
30
+ return if arguments.empty?
31
+
32
+ # get a dup of the args since will mock with the original
33
+ args = arguments.clone
34
+
35
+ # dump request info to mongo
36
+ save_log( save_feature( args ), args )
37
+ rescue => mole_boom
38
+ $stderr.puts "MOLE STORE CRAPPED OUT -- #{mole_boom}"
39
+ $stderr.puts mole_boom.backtrace.join( "\n " )
40
+ end
41
+
42
+ # =======================================================================
43
+ private
44
+
45
+ def init_mongo( opts )
46
+ @connection = Mongo::Connection.new( opts[:host], opts[:port], :logger => opts[:logger] )
47
+ @database = @connection.db( opts[:database] )
48
+ @features = database.collection( 'features' )
49
+ @logs = database.collection( 'logs' )
50
+ end
51
+
52
+ # Set up mongo default options ie localhost host, default mongo port and
53
+ # the database being mole_mdb
54
+ def default_options
55
+ {
56
+ :host => 'localhost',
57
+ :port => 27017,
58
+ :database => 'mole_mdb'
59
+ }
60
+ end
61
+
62
+ # Find or create a mole feature
63
+ def save_feature( args )
64
+ app_name = args.delete( :app_name )
65
+ route_info = args.delete( :route_info )
66
+ environment = args.delete( :environment )
67
+
68
+ row = { min_field(:app_name) => app_name, min_field(:env) => environment }
69
+ if route_info
70
+ row[min_field(:controller)] = route_info[:controller]
71
+ row[min_field(:action)] = route_info[:action]
72
+ else
73
+ row[min_field(:context)] = args.delete( :path )
74
+ end
75
+
76
+ feature = features.find_one( row )
77
+ return feature if feature
78
+
79
+ id = features.save( row )
80
+ features.find_one( id )
81
+ end
82
+
83
+ # Insert a new feature in the db
84
+ def save_log( feature, args )
85
+ type = FEATURE
86
+ type = EXCEPTION if args[:stack]
87
+ type = PERFORMANCE if args.delete(:performance)
88
+
89
+ # BOZO !! to reduce collection space...
90
+ # Using cryptic key to reduce storage needs.
91
+ # Also narrowing date/time to ints
92
+ now = Time.now
93
+ row = {
94
+ min_field( :type ) => type,
95
+ min_field( :feature_id ) => feature['_id'].to_s,
96
+ min_field( :date_id ) => ("%4d%02d%02d" %[now.year, now.month, now.day]).to_i,
97
+ min_field( :time_id ) => ("%02d%02d%02d" %[now.hour, now.min, now.sec] ).to_i
98
+ }
99
+
100
+ args.each do |k,v|
101
+ row[min_field(k)] = v if v
102
+ end
103
+ logs.save( row )
104
+ end
105
+
106
+ # For storage reason minify the json to save space...
107
+ def min_field( field )
108
+ field_map[field] || field
109
+ end
110
+
111
+ # Normalize all accessors to 3 chars.
112
+ def field_map
113
+ @field_map ||= {
114
+ :app_name => :app,
115
+ :context => :ctx,
116
+ :controller => :ctl,
117
+ :action => :act,
118
+ :type => :typ,
119
+ :feature_id => :fid,
120
+ :date_id => :did,
121
+ :time_id => :tid,
122
+ :user_id => :uid,
123
+ :user_name => :una,
124
+ :browser => :bro,
125
+ :host => :hos,
126
+ :software => :sof,
127
+ :request_time => :rti,
128
+ :performance => :per,
129
+ :method => :met,
130
+ :path => :pat,
131
+ :session => :ses,
132
+ :params => :par,
133
+ :ruby_version => :ver,
134
+ :stack => :sta
135
+ }
136
+ end
137
+ end
138
+ end
139
+ end
@@ -0,0 +1 @@
1
+ Rackamole.require_all_libs_relative_to(__FILE__)
data/lib/rackamole.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  module Rackamole
2
2
 
3
3
  # :stopdoc:
4
- VERSION = '0.0.4'
4
+ VERSION = '0.0.6'
5
5
  LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
6
6
  PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
7
7
  # :startdoc:
@@ -1,16 +1,16 @@
1
1
  require File.join(File.dirname(__FILE__), %w[.. spec_helper])
2
- require 'actionpack'
2
+ # require 'actionpack'
3
3
 
4
4
  describe Rack::Mole do
5
5
  include Rack::Test::Methods
6
6
 
7
7
  before :each do
8
8
  @response = [ 200, {"Content-Type" => "text/plain"}, ["success"] ]
9
+ @test_env = { 'rack.session' => { :user_id => 100 }, 'HTTP_X_FORWARDED_FOR' => '1.1.1.1', 'HTTP_USER_AGENT' => "Firefox" }
9
10
  end
10
11
 
11
12
  class TestStore
12
- attr_accessor :mole_result
13
-
13
+ attr_accessor :mole_result
14
14
  def mole( args )
15
15
  @mole_result = args
16
16
  end
@@ -24,11 +24,34 @@ describe Rack::Mole do
24
24
  run lambda { |env| response }
25
25
  end
26
26
  end
27
-
27
+
28
+ def error_app( opts={} )
29
+ @app ||= Rack::Builder.new do
30
+ use Rack::Lint
31
+ use Rack::Mole, opts
32
+ run lambda { |env| raise "Oh Snap!" }
33
+ end
34
+ end
35
+
36
+ it "should mole a framwework exception correctly" do
37
+ @test_store = TestStore.new
38
+ error_app(
39
+ :app_name => "Test App",
40
+ :environment => :test,
41
+ :perf_threshold => 0.1,
42
+ :user_key => { :session_key => :user_id, :extractor => lambda{ |k| "Test user #{k}"} },
43
+ :store => @test_store )
44
+
45
+ begin
46
+ get "/", nil, @test_env
47
+ rescue
48
+ @test_store.mole_result[:stack].should have(4).items
49
+ end
50
+ end
51
+
28
52
  describe 'moling a request' do
29
53
  before :each do
30
54
  @test_store = TestStore.new
31
- @test_env = { 'rack.session' => { :user_id => 100 }, 'HTTP_X_FORWARDED_FOR' => '1.1.1.1', 'HTTP_USER_AGENT' => "IBrowse" }
32
55
  app(
33
56
  :app_name => "Test App",
34
57
  :environment => :test,
@@ -44,11 +67,11 @@ describe Rack::Mole do
44
67
  @test_store.mole_result[:user_id].should == 100
45
68
  @test_store.mole_result[:user_name].should == 'Test user 100'
46
69
  @test_store.mole_result[:ip].should == '1.1.1.1'
47
- @test_store.mole_result[:browser].should == 'IBrowse'
70
+ @test_store.mole_result[:browser].should == 'Firefox'
48
71
  @test_store.mole_result[:method].should == 'GET'
49
72
  @test_store.mole_result[:url].should == 'http://example.org/'
50
73
  @test_store.mole_result[:path].should == '/'
51
- @test_store.mole_result[:perf_issue].should == false
74
+ @test_store.mole_result[:performance].should == false
52
75
  @test_store.mole_result[:params].should be_nil
53
76
  @test_store.mole_result[:session].should_not be_nil
54
77
  @test_store.mole_result[:session].should == { :user_id => '100' }
@@ -58,11 +81,11 @@ describe Rack::Mole do
58
81
  begin
59
82
  raise 'Oh snap!'
60
83
  rescue => boom
61
- get "/", nil, { 'mole.exception' => boom, 'rack.session' => { :user_id => 100 }, 'HTTP_X_FORWARDED_FOR' => '1.1.1.1', 'HTTP_USER_AGENT' => "IBrowse" }
84
+ get "/", nil, @test_env.merge( { 'mole.exception' => boom } )
62
85
  @test_store.mole_result[:stack].should have(4).items
63
86
  end
64
87
  end
65
-
88
+
66
89
  it "should capture request parameters correctly" do
67
90
  get "/", { :blee => 'duh' }, @test_env
68
91
  @test_store.mole_result[:params].should == { :blee => "duh".to_json }
@@ -72,7 +95,6 @@ describe Rack::Mole do
72
95
  describe 'username in session' do
73
96
  before :each do
74
97
  @test_store = TestStore.new
75
- @test_env = { 'rack.session' => { :user_name => "Fernand" } }
76
98
  app(
77
99
  :app_name => "Test App",
78
100
  :environment => :test,
@@ -81,10 +103,25 @@ describe Rack::Mole do
81
103
  :store => @test_store )
82
104
  end
83
105
 
84
- it "should mole the user correctly" do
85
- get "/", nil, @test_env
86
- @test_store.mole_result[:user_id].should be_nil
87
- @test_store.mole_result[:user_name].should == 'Fernand'
88
- end
106
+ it "should pickup the user name from the session correctly" do
107
+ get "/", nil, @test_env.merge( { 'rack.session' => { :user_name => "Fernand" } } )
108
+ @test_store.mole_result[:user_id].should be_nil
109
+ @test_store.mole_result[:user_name].should == 'Fernand'
110
+ end
111
+ end
112
+
113
+ describe '#id_browser' do
114
+ before :all do
115
+ @rack = Rack::Mole.new( nil )
116
+ end
117
+
118
+ it "should detect a browser type correctly" do
119
+ browser = @rack.send( :id_browser, "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648; InfoPath.2; MS-RTC LM 8; SPC 3.1 P1 Ta)")
120
+ browser.should == 'MSIE 7.0'
121
+ end
122
+
123
+ it "should return unknow if can't detect it" do
124
+ @rack.send( :id_browser, 'IBrowse' ).should == 'N/A'
125
+ end
89
126
  end
90
127
  end
@@ -1,5 +1,4 @@
1
1
  require File.join(File.dirname(__FILE__), %w[.. .. spec_helper])
2
- require 'mongo/util/ordered_hash'
3
2
 
4
3
  describe Rackamole::Store::Log do
5
4
  describe "#mole" do
@@ -0,0 +1,128 @@
1
+ require File.join(File.dirname(__FILE__), %w[.. .. spec_helper])
2
+
3
+ describe Rackamole::Store::MongoDb do
4
+
5
+ describe "#mole" do
6
+ before( :all ) do
7
+ @store = Rackamole::Store::MongoDb.new(
8
+ :host => 'localhost',
9
+ :port => 27017,
10
+ :database => 'test_mole_mdb',
11
+ :logger => Rackamole::Logger.new( :file_name => $stdout, :log_level => 'info' ) )
12
+ @db = @store.database
13
+ end
14
+
15
+ before( :each ) do
16
+ @store.reset!
17
+
18
+ @args = OrderedHash.new
19
+ @args[:app_name] = "Test app"
20
+ @args[:environment] = :test
21
+ @args[:perf_issue] = false
22
+ @args[:ip] = "1.1.1.1"
23
+ @args[:browser] = "Ibrowse"
24
+ @args[:user_id] = 100
25
+ @args[:user_name] = "Fernand"
26
+ @args[:request_time] = 1.0
27
+ @args[:url] = "http://test_me/"
28
+ @args[:path] = "/fred"
29
+ @args[:method] = 'GET'
30
+ @args[:params] = { :blee => "duh".to_json }
31
+ @args[:session] = { :fred => 10.to_json }
32
+ end
33
+
34
+ it "should mole a context based feature correctly" do
35
+ @store.mole( @args )
36
+ @store.features.count.should == 1
37
+ @store.logs.count.should == 1
38
+
39
+ feature = @store.features.find_one()
40
+ feature.should_not be_nil
41
+ feature['app'].should == 'Test app'
42
+ feature['env'].should == :test
43
+ feature['ctx'].should == '/fred'
44
+
45
+ log = @store.logs.find_one()
46
+ log.should_not be_nil
47
+ log['typ'].should == Rackamole::Store::MongoDb::FEATURE
48
+ log['fid'].should_not be_nil
49
+ log['par'].should == { 'blee' => 'duh'.to_json }
50
+ log['ip'].should == '1.1.1.1'
51
+ log['bro'].should == 'Ibrowse'
52
+ log['url'].should == 'http://test_me/'
53
+ log['met'].should == 'GET'
54
+ log['ses'].should == { 'fred' => '10' }
55
+ log['una'].should == 'Fernand'
56
+ log['uid'].should == 100
57
+ log['rti'].should == 1.0
58
+ log['did'].should_not be_nil
59
+ log['tid'].should_not be_nil
60
+
61
+ @store.features.find_one( Mongo::ObjectID.from_string( log['fid'] ) )['app'].should == 'Test app'
62
+ end
63
+
64
+ it "should mole a rails feature correctly" do
65
+ @args[:path] = '/fred/blee/duh'
66
+ @args[:route_info] = { :controller => 'fred', :action => 'blee', :id => 'duh' }
67
+ @store.mole( @args )
68
+
69
+ @store.features.count.should == 1
70
+ @store.logs.count.should == 1
71
+
72
+ feature = @store.features.find_one()
73
+ feature.should_not be_nil
74
+ feature['ctl'].should == 'fred'
75
+ feature['act'].should == 'blee'
76
+ feature['ctx'].should be_nil
77
+
78
+ log = @store.logs.find_one()
79
+ log.should_not be_nil
80
+ log['typ'].should == Rackamole::Store::MongoDb::FEATURE
81
+ log['pat'].should_not be_nil
82
+ end
83
+
84
+ it "should reuse an existing feature" do
85
+ @store.mole( @args )
86
+ @store.mole( @args )
87
+
88
+ @store.features.count.should == 1
89
+ @store.logs.count.should == 2
90
+ end
91
+
92
+ it "should mole perf correctly" do
93
+ @args[:performance] = true
94
+ @store.mole( @args )
95
+
96
+ @store.features.count.should == 1
97
+ @store.logs.count.should == 1
98
+
99
+ feature = @store.features.find_one()
100
+ feature.should_not be_nil
101
+
102
+ log = @store.logs.find_one()
103
+ log.should_not be_nil
104
+ log['typ'].should == Rackamole::Store::MongoDb::PERFORMANCE
105
+ end
106
+
107
+ it 'should mole an exception correctly' do
108
+ @args[:stack] = ['fred']
109
+ @store.mole( @args )
110
+
111
+ @store.features.count.should == 1
112
+ @store.logs.count.should == 1
113
+
114
+ feature = @store.features.find_one()
115
+ feature.should_not be_nil
116
+
117
+ log = @store.logs.find_one()
118
+ log.should_not be_nil
119
+ log['typ'].should == Rackamole::Store::MongoDb::EXCEPTION
120
+ log['sta'].should == ['fred']
121
+ end
122
+
123
+ it 'should keep count an similar exceptions or perf issues' do
124
+ pending "NYI"
125
+ end
126
+ end
127
+
128
+ end
data/tasks/rdoc.rake ADDED
@@ -0,0 +1,54 @@
1
+ require 'rake/rdoctask'
2
+ require 'darkfish-rdoc'
3
+
4
+ namespace :doc do
5
+
6
+ desc 'Generate RDoc documentation'
7
+ Rake::RDocTask.new do |rd|
8
+ rdoc = PROJ.rdoc
9
+ rd.main = rdoc.main
10
+ rd.rdoc_dir = rdoc.dir
11
+
12
+ incl = Regexp.new(rdoc.include.join('|'))
13
+ excl = Regexp.new(rdoc.exclude.join('|'))
14
+ files = PROJ.gem.files.find_all do |fn|
15
+ case fn
16
+ when excl; false
17
+ when incl; true
18
+ else false end
19
+ end
20
+ rd.rdoc_files.push(*files)
21
+
22
+ name = PROJ.name
23
+ rf_name = PROJ.rubyforge.name
24
+
25
+ title = "#{name}-#{PROJ.version} Documentation"
26
+ title = "#{rf_name}'s " + title if rf_name.valid? and rf_name != name
27
+
28
+ rd.options << "-t #{title}"
29
+ rd.options << "-SHN"
30
+ rd.options << "-f"
31
+ rd.options << "darkfish"
32
+ rd.options.concat(rdoc.opts)
33
+ end
34
+
35
+ desc 'Generate ri locally for testing'
36
+ task :ri => :clobber_ri do
37
+ sh "#{RDOC} --ri -o ri ."
38
+ end
39
+
40
+ task :clobber_ri do
41
+ rm_r 'ri' rescue nil
42
+ end
43
+
44
+ end # namespace :doc
45
+
46
+ desc 'Alias to doc:rdoc'
47
+ task :doc => 'doc:rdoc'
48
+
49
+ desc 'Remove all build products'
50
+ task :clobber => %w(doc:clobber_rdoc doc:clobber_ri)
51
+
52
+ remove_desc_for_task %w(doc:clobber_rdoc)
53
+
54
+ # EOF
data/tasks/setup.rb CHANGED
@@ -28,7 +28,7 @@ PROJ = OpenStruct.new(
28
28
  :ruby_opts => %w(-w),
29
29
  :libs => [],
30
30
  :history_file => 'History.txt',
31
- :readme_file => 'README.txt',
31
+ :readme_file => 'README.rdoc',
32
32
  :ignore_file => '.bnsignore',
33
33
 
34
34
  # Announce
data/tasks/spec.rake CHANGED
@@ -28,7 +28,7 @@ namespace :spec do
28
28
  t.spec_files = PROJ.spec.files
29
29
  t.libs += PROJ.libs
30
30
  t.rcov = true
31
- t.rcov_dir = PROJ.rcov.dir
31
+ t.rcov_dir = PROJ.rcov.dir
32
32
  t.rcov_opts = PROJ.rcov.opts + ['--exclude', 'spec']
33
33
  end
34
34
 
data/tasks/test.rake CHANGED
@@ -37,4 +37,4 @@ task :clobber => 'test:clobber_rcov' if HAVE_RCOV
37
37
 
38
38
  end
39
39
 
40
- # EOF
40
+ # EOF
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.0.4
4
+ version: 0.0.6
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-11-17 00:00:00 -07:00
12
+ date: 2009-11-21 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -33,14 +33,24 @@ dependencies:
33
33
  version: 1.0.3
34
34
  version:
35
35
  - !ruby/object:Gem::Dependency
36
- name: mongodb-mongo
36
+ name: mongo
37
37
  type: :runtime
38
38
  version_requirement:
39
39
  version_requirements: !ruby/object:Gem::Requirement
40
40
  requirements:
41
41
  - - ">="
42
42
  - !ruby/object:Gem::Version
43
- version: 0.14.1
43
+ version: 0.17.1
44
+ version:
45
+ - !ruby/object:Gem::Dependency
46
+ name: darkfish-rdoc
47
+ type: :runtime
48
+ version_requirement:
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 1.1.5
44
54
  version:
45
55
  - !ruby/object:Gem::Dependency
46
56
  name: bones
@@ -64,22 +74,18 @@ description: "The MOle is a rack application that monitors user interactions wit
64
74
  your coolest features are thought as such by your users. You will be able to elegantly record user\n\
65
75
  interactions and leverage these findings for the next iteration of your application. "
66
76
  email: fernand.galiana@gmail.com
67
- executables:
68
- - rackamole
77
+ executables: []
78
+
69
79
  extensions: []
70
80
 
71
81
  extra_rdoc_files:
72
- - History.txt
73
- - README.txt
82
+ - README.rdoc
74
83
  - aaa.txt
75
- - bin/rackamole
76
84
  - samples/rails/moled/public/robots.txt
77
85
  files:
78
- - History.txt
79
- - README.txt
86
+ - README.rdoc
80
87
  - Rakefile
81
88
  - aaa.txt
82
- - bin/rackamole
83
89
  - images/mole_logo.png
84
90
  - images/mole_logo.psd
85
91
  - images/mole_logo_small.png
@@ -88,8 +94,9 @@ files:
88
94
  - lib/rackamole/interceptor.rb
89
95
  - lib/rackamole/logger.rb
90
96
  - lib/rackamole/mole.rb
97
+ - lib/rackamole/store.rb
91
98
  - lib/rackamole/store/log.rb
92
- - lib/rackamole/store/mongo.rb
99
+ - lib/rackamole/store/mongo_db.rb
93
100
  - samples/rails/moled/README
94
101
  - samples/rails/moled/Rakefile
95
102
  - samples/rails/moled/app/controllers/application_controller.rb
@@ -152,7 +159,7 @@ files:
152
159
  - spec/rackamole/logger_spec.rb
153
160
  - spec/rackamole/mole_spec.rb
154
161
  - spec/rackamole/store/log_spec.rb
155
- - spec/rackamole/store/mongo_spec.rb
162
+ - spec/rackamole/store/mongo_db_spec.rb
156
163
  - spec/rackamole_spec.rb
157
164
  - spec/spec_helper.rb
158
165
  - tasks/bones.rake
@@ -160,6 +167,7 @@ files:
160
167
  - tasks/git.rake
161
168
  - tasks/notes.rake
162
169
  - tasks/post_load.rake
170
+ - tasks/rdoc.rake
163
171
  - tasks/rubyforge.rake
164
172
  - tasks/setup.rb
165
173
  - tasks/spec.rake
@@ -173,7 +181,7 @@ licenses: []
173
181
  post_install_message:
174
182
  rdoc_options:
175
183
  - --main
176
- - README.txt
184
+ - README.rdoc
177
185
  require_paths:
178
186
  - lib
179
187
  required_ruby_version: !ruby/object:Gem::Requirement
data/History.txt DELETED
@@ -1,3 +0,0 @@
1
- == 0.0.2 / 2009-11-11
2
-
3
- * Hello World...
data/bin/rackamole DELETED
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require File.expand_path(
4
- File.join(File.dirname(__FILE__), %w[.. lib rackamole]))
5
-
6
- # Put your code here
7
-
8
- # EOF
@@ -1,121 +0,0 @@
1
- require 'mongo'
2
-
3
- include Mongo
4
-
5
- # TODO !! Need to deal with auth
6
- module Rackamole
7
- module Store
8
- # Mongo adapter. Stores mole info in a mongo database.
9
- # Two collections are available namely features and logs. Logs references
10
- # the features collection.
11
- class Mongo
12
-
13
- attr_reader :connection
14
-
15
- def initialize( options={} )
16
- opts = default_options.merge( options )
17
- @connection = Connection.new( opts[:host], opts[:port] ).db( opts[:database] )
18
- end
19
-
20
- # clear out db content
21
- def reset!
22
- features.clear
23
- logs.clear
24
- end
25
-
26
- # Dump mole info to logger
27
- def mole( args )
28
- return if args.empty?
29
-
30
- feature = find_or_create_feature( args )
31
- log_feature( feature, args )
32
- rescue => mole_boom
33
- $stderr.puts "MOLE STORE CRAPPED OUT -- #{mole_boom}"
34
- $stderr.puts mole_boom.backtrace.join( "\n " )
35
- end
36
-
37
- # Convenience to access mole features cltn
38
- def features
39
- @features ||= @connection['features']
40
- end
41
-
42
- # Convenience to access mole log cltn
43
- def logs
44
- @logs ||= @connection['logs']
45
- end
46
-
47
- # =======================================================================
48
- private
49
-
50
- # Set up mongo default options ie localhost host, default mongo port and
51
- # the database being mole_mdb
52
- def default_options
53
- {
54
- :host => 'localhost',
55
- :port => 27017,
56
- :database => 'mole_mdb'
57
- }
58
- end
59
-
60
- # retrieves a feature if exists or create a new one otherwise
61
- def find_or_create_feature( args )
62
- if args[:route_info]
63
- controller = args[:route_info][:controller]
64
- action = args[:route_info][:action]
65
- end
66
-
67
- feature = find_feature( args[:app_name], args[:path], controller, action )
68
-
69
- # Got one
70
- return feature if feature
71
-
72
- # If not create a new feature
73
- row = { :app_name => args[:app_name] }
74
- if controller and action
75
- row['controller'] = controller
76
- row['action'] = action
77
- else
78
- row['context'] = args[:path]
79
- end
80
- row['created_at'] = Time.now
81
- row['updated_at'] = Time.now
82
- features.insert( row )
83
- end
84
-
85
- # Attempt to find a mole feature
86
- def find_feature( app_name, path, controller, action )
87
- conds = { 'app_name' => app_name }
88
-
89
- # For rails use controller/action
90
- if controller and action
91
- conds['controller'] = controller
92
- conds['action'] = action
93
- # otherwise use path...
94
- else
95
- conds['context'] = path
96
- end
97
- features.find_one( conds )
98
- end
99
-
100
- # Insert a new feature in the db
101
- def log_feature( feature, args )
102
- type = 'Feature'
103
- type = 'Exception' if args[:stack]
104
- type = 'Performance' if args[:performance]
105
-
106
- row = {
107
- :type => type,
108
- :feature => ::DBRef.new( 'features', feature.instance_of?( ObjectID ) ? feature : feature['_id'] ),
109
- :created_at => Time.now,
110
- :updated_at => Time.now
111
- }
112
-
113
- skip_cols = [:app_name]
114
- args.each do |k,v|
115
- row[k] = v unless skip_cols.include?( k )
116
- end
117
- logs.insert( row )
118
- end
119
- end
120
- end
121
- end
@@ -1,120 +0,0 @@
1
- require File.join(File.dirname(__FILE__), %w[.. .. spec_helper])
2
- require 'mongo/util/ordered_hash'
3
-
4
- describe Rackamole::Store::Mongo do
5
-
6
- describe "#mole" do
7
- before( :each ) do
8
- @store = Rackamole::Store::Mongo.new( :host => 'localhost', :port => 27017, :database => 'test_mole_mdb' )
9
- @store.reset!
10
-
11
- @args = OrderedHash.new
12
- @args[:app_name] = "Test app"
13
- @args[:environment] = :test
14
- @args[:perf_issue] = false
15
- @args[:ip] = "1.1.1.1"
16
- @args[:browser] = "Ibrowse"
17
- @args[:user_id] = 100
18
- @args[:user_name] = "Fernand"
19
- @args[:request_time] = 1.0
20
- @args[:url] = "http://test_me/"
21
- @args[:path] = "/fred"
22
- @args[:method] = 'GET'
23
- @args[:params] = { :blee => "duh".to_json }
24
- @args[:session] = { :fred => 10.to_json }
25
- end
26
-
27
- it "should mole a feature correctly" do
28
- @store.mole( @args )
29
- @store.features.count.should == 1
30
- @store.logs.count.should == 1
31
-
32
- feature = @store.features.find_one( {} )
33
- feature.should_not be_nil
34
- feature['app_name'].should == 'Test app'
35
- feature['context'].should == '/fred'
36
- feature['created_at'].should_not be_nil
37
- feature['updated_at'].should_not be_nil
38
-
39
- log = @store.logs.find_one( {} )
40
- log.should_not be_nil
41
- log['params'].should == { 'blee' => 'duh'.to_json }
42
- log['ip'].should == '1.1.1.1'
43
- log['browser'].should == 'Ibrowse'
44
- log['environment'].should == :test
45
- log['path'].should == '/fred'
46
- log['url'].should == 'http://test_me/'
47
- log['method'].should == 'GET'
48
- log['session'].should == { 'fred' => '10' }
49
- log['user_name'].should == 'Fernand'
50
- log['user_id'].should == 100
51
- log['request_time'].should == 1.0
52
- log['perf_issue'].should == false
53
- log['created_at'].should_not be_nil
54
- log['updated_at'].should_not be_nil
55
- @store.connection.dereference( log['feature'] )['app_name'].should == 'Test app'
56
- end
57
-
58
- it "should mole a rails feature correctly" do
59
- @args[:path] = '/fred/blee/duh'
60
- @args[:route_info] = { :controller => 'fred', :action => 'blee', :id => 'duh' }
61
- @store.mole( @args )
62
-
63
- @store.features.count.should == 1
64
- @store.logs.count.should == 1
65
-
66
- feature = @store.features.find_one( {} )
67
- feature.should_not be_nil
68
- feature['controller'].should == 'fred'
69
- feature['action'].should == 'blee'
70
- feature['context'].should be_nil
71
-
72
- log = @store.logs.find_one( {} )
73
- log.should_not be_nil
74
- log['route_info'].should_not be_nil
75
- end
76
-
77
- it "should reuse an existing feature" do
78
- @store.mole( @args )
79
- @store.mole( @args )
80
-
81
- @store.features.count.should == 1
82
- @store.logs.count.should == 2
83
- end
84
-
85
- it "should mole perf correctly" do
86
- @args[:perf_issue] = true
87
- @store.mole( @args )
88
-
89
- @store.features.count.should == 1
90
- @store.logs.count.should == 1
91
-
92
- feature = @store.features.find_one( {} )
93
- feature.should_not be_nil
94
-
95
- log = @store.logs.find_one( {} )
96
- log.should_not be_nil
97
- log['perf_issue'].should == true
98
- end
99
-
100
- it 'should mole an exception correctly' do
101
- @args[:exception] = ['fred']
102
- @store.mole( @args )
103
-
104
- @store.features.count.should == 1
105
- @store.logs.count.should == 1
106
-
107
- feature = @store.features.find_one( {} )
108
- feature.should_not be_nil
109
-
110
- log = @store.logs.find_one( {} )
111
- log.should_not be_nil
112
- log['exception'].should == ['fred']
113
- end
114
-
115
- it 'should keep count an similar exceptions or perf issues' do
116
- pending "NYI"
117
- end
118
- end
119
-
120
- end