wackamole 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.
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
+ }