wackamole 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (146) hide show
  1. data/.bnsignore +16 -0
  2. data/.gitignore +2 -0
  3. data/History.txt +4 -0
  4. data/README.rdoc +88 -0
  5. data/Rakefile +42 -0
  6. data/aa.rb +25 -0
  7. data/aaa.txt +13 -0
  8. data/bin/wackamole +77 -0
  9. data/lib/app.rb +63 -0
  10. data/lib/controllers/dashboard.rb +30 -0
  11. data/lib/controllers/features.rb +41 -0
  12. data/lib/controllers/logs.rb +49 -0
  13. data/lib/controllers/mission.rb +27 -0
  14. data/lib/controllers/users.rb +41 -0
  15. data/lib/helpers/dashboard_helper.rb +32 -0
  16. data/lib/helpers/features_helper.rb +13 -0
  17. data/lib/helpers/flash_helper.rb +16 -0
  18. data/lib/helpers/logs_helper.rb +116 -0
  19. data/lib/helpers/main_helper.rb +182 -0
  20. data/lib/helpers/mission_helper.rb +59 -0
  21. data/lib/helpers/rails_helper.rb +7 -0
  22. data/lib/wackamole.rb +47 -0
  23. data/lib/wackamole/core_ext/date_time.rb +8 -0
  24. data/lib/wackamole/core_ext/time.rb +9 -0
  25. data/lib/wackamole/models/control.rb +132 -0
  26. data/lib/wackamole/models/feature.rb +74 -0
  27. data/lib/wackamole/models/log.rb +45 -0
  28. data/lib/wackamole/models/mission.rb +164 -0
  29. data/lib/wackamole/models/mole_info.rb +94 -0
  30. data/lib/wackamole/models/search_filter.rb +192 -0
  31. data/lib/wackamole/models/user.rb +46 -0
  32. data/public/favicon.ico +0 -0
  33. data/public/images/.DS_Store +0 -0
  34. data/public/images/browsers/.DS_Store +0 -0
  35. data/public/images/browsers/MSIE 6.png +0 -0
  36. data/public/images/browsers/MSIE 8.0 +0 -0
  37. data/public/images/browsers/MSIE 8.0.png +0 -0
  38. data/public/images/browsers/chrome.png +0 -0
  39. data/public/images/browsers/firefox.png +0 -0
  40. data/public/images/browsers/ie 6.0.png +0 -0
  41. data/public/images/browsers/ie6.jpg +0 -0
  42. data/public/images/browsers/ie7.jpg +0 -0
  43. data/public/images/browsers/ie7.png +0 -0
  44. data/public/images/browsers/msie 6.0.png +0 -0
  45. data/public/images/browsers/msie 7.0.png +0 -0
  46. data/public/images/browsers/opera.jpg +0 -0
  47. data/public/images/browsers/opera.png +0 -0
  48. data/public/images/browsers/safari.jpg +0 -0
  49. data/public/images/browsers/safari.png +0 -0
  50. data/public/images/browsers/unknown_browser.png +0 -0
  51. data/public/images/close.png +0 -0
  52. data/public/images/error.png +0 -0
  53. data/public/images/fade.png +0 -0
  54. data/public/images/fault_big.png +0 -0
  55. data/public/images/fault_small.png +0 -0
  56. data/public/images/feature.png +0 -0
  57. data/public/images/h300.png +0 -0
  58. data/public/images/hori_large.png +0 -0
  59. data/public/images/info_big.png +0 -0
  60. data/public/images/info_small.png +0 -0
  61. data/public/images/loading.gif +0 -0
  62. data/public/images/loading1.gif +0 -0
  63. data/public/images/mole_error.png +0 -0
  64. data/public/images/more.gif +0 -0
  65. data/public/images/next.png +0 -0
  66. data/public/images/perf_big.png +0 -0
  67. data/public/images/perf_small.png +0 -0
  68. data/public/images/powered_by.png +0 -0
  69. data/public/images/prev.png +0 -0
  70. data/public/images/row_fade.png +0 -0
  71. data/public/images/search.png +0 -0
  72. data/public/images/small_logo.png +0 -0
  73. data/public/images/spaceball.gif +0 -0
  74. data/public/images/tick.png +0 -0
  75. data/public/images/users.png +0 -0
  76. data/public/images/wackamole_logo.png +0 -0
  77. data/public/javascripts/.DS_Store +0 -0
  78. data/public/javascripts/application.js +28 -0
  79. data/public/javascripts/g.dot.min.js +7 -0
  80. data/public/javascripts/g.raphael.min.js +7 -0
  81. data/public/javascripts/jit.js +9052 -0
  82. data/public/javascripts/jit.min.js +1 -0
  83. data/public/javascripts/jquery-ui.js +188 -0
  84. data/public/javascripts/jquery.example.js +160 -0
  85. data/public/javascripts/jquery.js +19 -0
  86. data/public/javascripts/jquery.tools.min.js +38 -0
  87. data/public/javascripts/jquery_ba-url.js +9 -0
  88. data/public/javascripts/jquery_min.js +19 -0
  89. data/public/javascripts/jquery_ui_min.js +298 -0
  90. data/public/javascripts/raphael.min.js +7 -0
  91. data/public/stylesheets/tabs-slideshow.css +95 -0
  92. data/public/stylesheets/wackamole.css +684 -0
  93. data/spec/config/bogus_test.yml +3 -0
  94. data/spec/config/test.yml +3 -0
  95. data/spec/core_ext/date_time_spec.rb +8 -0
  96. data/spec/core_ext/time_spec.rb +12 -0
  97. data/spec/data/fixtures.rb +92 -0
  98. data/spec/models/control_spec.rb +98 -0
  99. data/spec/models/feature_spec.rb +52 -0
  100. data/spec/models/log_spec.rb +43 -0
  101. data/spec/models/mission_spec.rb +225 -0
  102. data/spec/models/moled_info_spec.rb +30 -0
  103. data/spec/models/search_filter_spec.rb +151 -0
  104. data/spec/models/user_spec.rb +44 -0
  105. data/spec/spec_helper.rb +14 -0
  106. data/spec/wackamole_spec.rb +20 -0
  107. data/tasks/bones.rake +20 -0
  108. data/tasks/fixtures.rake +13 -0
  109. data/tasks/gem.rake +201 -0
  110. data/tasks/git.rake +40 -0
  111. data/tasks/notes.rake +27 -0
  112. data/tasks/post_load.rake +32 -0
  113. data/tasks/rdoc.rake +54 -0
  114. data/tasks/rubyforge.rake +55 -0
  115. data/tasks/setup.rb +290 -0
  116. data/tasks/spec.rake +54 -0
  117. data/tasks/svn.rake +46 -0
  118. data/views/dashboard/_report.erb +118 -0
  119. data/views/dashboard/index.erb +4 -0
  120. data/views/dashboard/refresh_js.erb +3 -0
  121. data/views/features/_rows.erb +26 -0
  122. data/views/features/filter.js.erb +2 -0
  123. data/views/features/index.erb +24 -0
  124. data/views/features/index.js.erb +2 -0
  125. data/views/layout.erb +47 -0
  126. data/views/logs/_array.erb +12 -0
  127. data/views/logs/_hash.erb +14 -0
  128. data/views/logs/_rows.erb +65 -0
  129. data/views/logs/filter.js.erb +4 -0
  130. data/views/logs/index.erb +13 -0
  131. data/views/logs/index.js.erb +2 -0
  132. data/views/logs/show.erb +66 -0
  133. data/views/mission/_report.erb +49 -0
  134. data/views/mission/index.erb +7 -0
  135. data/views/mission/refresh_js.erb +3 -0
  136. data/views/shared/_filter.erb +63 -0
  137. data/views/shared/_flash.erb +3 -0
  138. data/views/shared/_search.erb +25 -0
  139. data/views/shared/_timestamp.erb +1 -0
  140. data/views/shared/_wait.erb +1 -0
  141. data/views/shared/flash.js.erb +10 -0
  142. data/views/users/_rows.erb +26 -0
  143. data/views/users/filter.js.erb +4 -0
  144. data/views/users/index.erb +24 -0
  145. data/views/users/index.js.erb +2 -0
  146. metadata +347 -0
@@ -0,0 +1,94 @@
1
+ require 'benchmark'
2
+
3
+ module Wackamole
4
+ class MoledInfo
5
+
6
+ def self.logs_cltn() Wackamole::Control.collection( 'logs' ) ; end
7
+ def self.users_cltn() Wackamole::Control.collection( 'users' ); end
8
+ def self.features_cltn() Wackamole::Control.collection( 'features' ); end
9
+
10
+ # ---------------------------------------------------------------------------
11
+ # Collect various data points to power up dashboard
12
+ # TODO - PERF - try just using cursor vs to_a
13
+ def self.collect_dashboard_info( now )
14
+ info = {}
15
+ day_logs = logs_cltn.find( { :did => now.to_date_id.to_s }, :fields => [:typ, :fid, :tid, :did, :uid] ).to_a
16
+
17
+ # Fetch user count for this hour
18
+ users = day_logs.inject( Set.new ) do |set,log|
19
+ set << log['uid'] if log['tid'] =~ /^#{"%02d" % now.hour}/
20
+ set
21
+ end
22
+ info[:total_users] = users_cltn.count
23
+ info[:user_load] = users.size
24
+
25
+ # Fetch features for this hour
26
+ features = day_logs.inject( Set.new ) do |set,log|
27
+ set << log['fid'].to_s if log['tid'] =~ /^#{"%02d" % now.hour}/
28
+ set
29
+ end
30
+ info[:total_features] = features_cltn.count
31
+ info[:feature_load] = features.size
32
+
33
+ info[:perf_load] = day_logs.inject(0) do |count,log|
34
+ if log['tid'] =~ /^#{"%02d" % now.hour}/
35
+ count += (log['typ'] == Rackamole.perf ? 1 : 0 )
36
+ end
37
+ count
38
+ end
39
+ info[:fault_load] = day_logs.inject(0) do |count,log|
40
+ if log['tid'] =~ /^#{"%02d" % now.hour}/
41
+ count += (log['typ'] == Rackamole.fault ? 1 : 0 )
42
+ end
43
+ count
44
+ end
45
+
46
+ # Count all logs per hourly time period
47
+ times = (0...24).to_a
48
+ time_info = times.inject(OrderedHash.new) { |res,time| res[time] = { :user => 0, :feature => 0, :perf => 0, :fault => 0 };res }
49
+ user_per_hour = {}
50
+ day_logs.each do |log|
51
+ date_tokens = log['did'].match( /(\d{4})(\d{2})(\d{2})/ ).captures
52
+ time_tokens = log['tid'].match( /(\d{2})(\d{2})(\d{2})/ ).captures
53
+ utc = Time.utc( date_tokens[0], date_tokens[1], date_tokens[2], time_tokens[0], time_tokens[1], time_tokens[2] )
54
+ time = utc.getlocal.hour
55
+ if user_per_hour[time]
56
+ unless user_per_hour[time].include? log['uid']
57
+ time_info[time][:user] += 1
58
+ user_per_hour[time] << log['uid']
59
+ end
60
+ else
61
+ user_per_hour[time] = [ log['uid'] ]
62
+ time_info[time][:user] += 1
63
+ end
64
+ case log['typ']
65
+ when Rackamole.feature : time_info[time][:feature] += 1 if features.add?( log['fid'])
66
+ when Rackamole.perf : time_info[time][:perf] += 1
67
+ when Rackamole.fault : time_info[time][:fault] += 1
68
+ end
69
+ end
70
+
71
+ # BOZO !! LAME ASS...
72
+ info[:user_series] = []
73
+ info[:fault_series] = []
74
+ info[:perf_series] = []
75
+ info[:feature_series] = []
76
+ time_info.values.map do |hash|
77
+ info[:user_series] << hash[:user]
78
+ info[:fault_series] << hash[:fault]
79
+ info[:perf_series] << hash[:perf]
80
+ info[:feature_series] << hash[:feature]
81
+ end
82
+ info
83
+ end
84
+
85
+ # ===========================================================================
86
+ private
87
+
88
+ # -------------------------------------------------------------------------
89
+ # Makes sure we have some indexes set
90
+ # BOZO !! Create script to set these up ?
91
+ def self.ensure_indexes
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,192 @@
1
+ require 'chronic'
2
+
3
+ module Wackamole
4
+ class SearchFilter
5
+
6
+ attr_accessor :time_frame, :feature_id, :type, :browser_type, :search_terms
7
+
8
+ # ---------------------------------------------------------------------------
9
+ # Ctor
10
+ def initialize
11
+ reset!
12
+ end
13
+
14
+ # ---------------------------------------------------------------------------
15
+ # Reset filter to defaults
16
+ def reset!
17
+ @feature_id = -1
18
+ @time_frame = SearchFilter.time_frames.first
19
+ @browser_type = SearchFilter.browser_types.first
20
+ @type = SearchFilter.mole_types.first
21
+ @search_terms = ""
22
+ end
23
+
24
+ # ---------------------------------------------------------------------------
25
+ # Available browsers
26
+ def self.browser_types
27
+ @browsers ||= [ 'All', 'Unknown', 'Firefox', 'Safari', 'MSIE 8.0', 'MSIE 7.0', 'MSIE 6.0', 'Opera', 'Chrome' ]
28
+ end
29
+
30
+ # ---------------------------------------------------------------------------
31
+ # Available time frames
32
+ def self.time_frames
33
+ @time_frames ||= ['today', '2 days', '1 week', '2 weeks', '1 month', '3 months', '6 months', '1 year' ]
34
+ end
35
+
36
+ # ---------------------------------------------------------------------------
37
+ # Collection of mole types
38
+ def self.mole_types
39
+ @types ||= %w[All Feature Perf Fault]
40
+ end
41
+
42
+ # ---------------------------------------------------------------------------
43
+ # Find all features
44
+ def features
45
+ features = Feature.features_cltn.find().to_a
46
+ features = features.map { |f| [context_for(f), f['_id']] }
47
+ features.sort! { |a,b| a.first <=> b.first }
48
+ features.insert( 0, ["All", -1] )
49
+ end
50
+
51
+ # ---------------------------------------------------------------------------
52
+ # Retrieves feature context
53
+ def context_for( f )
54
+ return "#{f['ctl']}##{f['act']}" if f['ctl']
55
+ f['ctx']
56
+ end
57
+
58
+ # ---------------------------------------------------------------------------
59
+ # Fetch filter start date id
60
+ def from_date_id
61
+ start = Chronic.parse( time_frame + ( time_frame == SearchFilter.time_frames.first ? "" : " ago" ) )
62
+ start.to_date_id
63
+ end
64
+
65
+ # ---------------------------------------------------------------------------
66
+ # fetch time series from time frame
67
+ def time_ids
68
+ now = Time.now
69
+ start = Chronic.parse( time_frame + ( time_frame == SearchFilter.time_frames.first ? "" : " ago" ) )
70
+ corpus_end = DateTime.new( now.year, now.month, now.day )
71
+ corpus_start = DateTime.new( start.year, start.month, start.day )
72
+
73
+ calc_date = corpus_start
74
+ time_series = []
75
+ while calc_date <= corpus_end do
76
+ time_series << calc_date.to_date_id
77
+ calc_date += 1
78
+ end
79
+ time_series
80
+ end
81
+
82
+ # ---------------------------------------------------------------------------
83
+ # fetch time series from time frame
84
+ def time_series
85
+ now = Time.now
86
+ start = Chronic.parse( time_frame + ( time_frame == SearchFilter.time_frames.first ? "" : " ago" ) )
87
+ corpus_end = DateTime.new( now.year, now.month, now.day )
88
+ corpus_start = DateTime.new( start.year, start.month, start.day )
89
+
90
+ calc_date = corpus_start
91
+ time_series = []
92
+ while calc_date <= corpus_end do
93
+ time_series << calc_date.strftime( "%Y-%m-%d" )
94
+ calc_date += 1
95
+ end
96
+ time_series
97
+ end
98
+
99
+ # ---------------------------------------------------------------------------
100
+ # Populate filter from request params
101
+ def from_options( options )
102
+ return unless options
103
+ options.each_pair do |k,v|
104
+ # value = k.index( /_id$/) ? v.to_i : v
105
+ self.send( "#{k}=", v )
106
+ end
107
+ end
108
+
109
+ # ---------------------------------------------------------------------------
110
+ # Spews filter conditions
111
+ def to_conds
112
+ conds = {}
113
+
114
+ # filter mole_types
115
+ if type != 'All'
116
+ conds[:typ] = map_mole_type( type )
117
+ end
118
+
119
+ if browser_type != 'All'
120
+ conds[:bro] = browser_type
121
+ end
122
+
123
+ # filter mole_features
124
+ unless feature_id.to_s == "-1"
125
+ conds[:fid] = Mongo::ObjectID.from_string( feature_id )
126
+ end
127
+
128
+ # filter by date
129
+ time = Chronic.parse( time_frame + ( time_frame == SearchFilter.time_frames.first ? "" : " ago" ) )
130
+ conds[:did] = { '$gte' => time.to_date_id.to_s }
131
+
132
+ unless search_terms.empty?
133
+ tokens = search_terms.split( ":" ).collect{ |c| c.strip }
134
+ key = tokens.shift
135
+ if key
136
+ if key == "user"
137
+ users = Wackamole::User.users_cltn.find( { :una => Regexp.new( tokens.first ) }, :fields => ['_id'] )
138
+ conds[field_map( key )] = { '$in' => users.collect{ |u| u['_id'] } }
139
+ elsif tokens.size == 2
140
+ conds["#{field_map(key)}.#{tokens.first}"] = Regexp.new( tokens.last )
141
+ elsif tokens.size == 1
142
+ conds[field_map(key)] = Regexp.new( tokens.first )
143
+ else
144
+ raise "Unable to evaluate search terms"
145
+ end
146
+ end
147
+ end
148
+ conds
149
+ end
150
+
151
+ # ===========================================================================
152
+ private
153
+
154
+ # ---------------------------------------------------------------------------
155
+ # Search filter key name map
156
+ def field_map( key )
157
+ case key.to_sym
158
+ when :user : :uid
159
+ when :method : :met
160
+ when :host : :hos
161
+ when :session : :ses
162
+ when :params : :par
163
+ else key
164
+ end
165
+ end
166
+
167
+ # Map named type to fixnum value
168
+ def map_mole_type( type )
169
+ case type
170
+ when 'Feature'
171
+ Rackamole.feature
172
+ when 'Perf'
173
+ Rackamole.perf
174
+ when 'Fault'
175
+ Rackamole.fault
176
+ else
177
+ raise "Invalid mole type `#{type}"
178
+ end
179
+ end
180
+
181
+ # ---------------------------------------------------------------------------
182
+ # Zeroed out now
183
+ def now
184
+ to_zero_hour( Time.now )
185
+ end
186
+
187
+ # Zeros out time info
188
+ def to_zero_hour( time )
189
+ Time.gm( time.year, time.month, time.day, 0, 0, 0 )
190
+ end
191
+ end
192
+ end
@@ -0,0 +1,46 @@
1
+ require 'will_paginate/collection'
2
+
3
+ module Wackamole
4
+ class User
5
+
6
+ def self.logs_cltn() Wackamole::Control.collection( 'logs' ) ; end
7
+ def self.users_cltn() Wackamole::Control.collection( 'users' ); end
8
+
9
+ # Pagination size
10
+ def self.default_page_size() @page_size ||= 20; end
11
+
12
+ # ---------------------------------------------------------------------------
13
+ # Find all users matching criteria and returns pagination collection
14
+ def self.paginate_tops( conds, page=1, page_size=default_page_size )
15
+ tops = logs_cltn.group( [:uid], conds, { :count => 0 }, 'function(obj,prev) { prev.count += 1}', true )
16
+ users = []
17
+ tops.sort{ |a,b| b['count'] <=> a['count'] }.each do |row|
18
+ users << { :uid => row['uid'], :total => row['count'].to_i, :details => [] }
19
+ end
20
+
21
+ WillPaginate::Collection.create( page, page_size, users.size ) do |pager|
22
+ offset = (page-1)*page_size
23
+ result = users[offset...(offset+page_size)]
24
+ result.each do |u|
25
+ user = users_cltn.find_one( u[:uid] ) #, :fields => [:una] )
26
+ raise "Unable to find user with id `#{u[:uid].inspect}" unless user
27
+ u[:name] = user['una']
28
+ end
29
+ pager.replace( result )
30
+ end
31
+ end
32
+
33
+ # ---------------------------------------------------------------------------
34
+ # Make sure indexes are setup for users
35
+ def self.ensure_indexes!
36
+ indexes = users_cltn.index_information
37
+ created_count = 0
38
+
39
+ unless indexes.has_key?( :una )
40
+ users_cltn.create_index( :una )
41
+ created_count += 1
42
+ end
43
+ created_count
44
+ end
45
+ end
46
+ end
File without changes
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,28 @@
1
+ function truncate(str, limit)
2
+ {
3
+ var bits, i;
4
+ bits = str.split('');
5
+ if (bits.length > limit) {
6
+ for (i = bits.length - 1; i > -1; --i) {
7
+ if (i > limit) {
8
+ bits.length = i;
9
+ }
10
+ else if (' ' === bits[i]) {
11
+ bits.length = i;
12
+ break;
13
+ }
14
+ }
15
+ bits.push('...');
16
+ }
17
+ return bits.join('');
18
+ }
19
+
20
+
21
+ function blee( url )
22
+ {
23
+ if( url == "/explore")
24
+ window.location = url;
25
+ else
26
+ $.ajax( {url: url, dataType: 'script', method: 'GET'} );
27
+ return false;
28
+ }