wackamole 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +8 -1
- data/lib/app.rb +1 -1
- data/lib/controllers/dashboard.rb +17 -9
- data/lib/controllers/features.rb +1 -5
- data/lib/controllers/logs.rb +3 -12
- data/lib/controllers/mission.rb +15 -0
- data/lib/controllers/users.rb +1 -7
- data/lib/helpers/mission_helper.rb +1 -4
- data/lib/wackamole/models/mission.rb +18 -20
- data/lib/wackamole/models/mole_info.rb +36 -59
- data/lib/wackamole/models/search_filter.rb +15 -2
- data/lib/wackamole.rb +1 -1
- data/public/javascripts/application.js +48 -7
- data/public/stylesheets/wackamole.css +4 -4
- data/spec/models/moled_info_spec.rb +1 -1
- data/views/dashboard/_report.erb +31 -48
- data/views/dashboard/index.erb +1 -1
- data/views/dashboard/refresh_js.erb +2 -1
- data/views/mission/_report.erb +2 -2
- data/views/shared/_filter.erb +17 -7
- data/views/shared/_timestamp.erb +1 -1
- metadata +2 -2
data/History.txt
CHANGED
@@ -17,4 +17,11 @@
|
|
17
17
|
* Add set_indexes script. Use to setup mole db indexes
|
18
18
|
|
19
19
|
=== 0.0.5 / 2010-02-08
|
20
|
-
* Added debug
|
20
|
+
* Added debug
|
21
|
+
|
22
|
+
=== 0.0.6 / 2010-02-08
|
23
|
+
* Bug fixes
|
24
|
+
|
25
|
+
=== 0.0.7 /2010-02-21
|
26
|
+
* Added drilldown on dashboard
|
27
|
+
* Bug fixes and clean up
|
data/lib/app.rb
CHANGED
@@ -46,7 +46,7 @@ configure do
|
|
46
46
|
:server => "%s:%d/%s/%s" % ['localhost', '27017', 'wackamole_ses', 'sessions'],
|
47
47
|
:log_level => :error
|
48
48
|
end
|
49
|
-
|
49
|
+
Wackamole::Control.init_config( default_config, Sinatra::Application.environment.to_s )
|
50
50
|
end
|
51
51
|
|
52
52
|
# -----------------------------------------------------------------------------
|
@@ -8,7 +8,7 @@ module Dashboard
|
|
8
8
|
get '/dashboard/:app_name/:stage' do
|
9
9
|
Wackamole::Control.switch_mole_db!( params[:app_name].downcase, params[:stage] )
|
10
10
|
|
11
|
-
|
11
|
+
@info = Wackamole::MoledInfo.collect_dashboard_info( @updated_on )
|
12
12
|
|
13
13
|
# Reset app info
|
14
14
|
load_app_info
|
@@ -22,21 +22,29 @@ module Dashboard
|
|
22
22
|
# ---------------------------------------------------------------------------
|
23
23
|
# Refresh dashboard
|
24
24
|
get '/dashboard/refresh' do
|
25
|
-
|
25
|
+
@info = Wackamole::MoledInfo.collect_dashboard_info( @updated_on )
|
26
|
+
|
26
27
|
erb :'dashboard/refresh_js', :layout => false
|
27
28
|
end
|
28
|
-
|
29
|
+
|
29
30
|
# ---------------------------------------------------------------------------
|
30
|
-
get '/dashboard/logs/:
|
31
|
-
|
32
|
-
load_app_details
|
33
|
-
load_app_info
|
34
|
-
|
31
|
+
get '/dashboard/logs/:type/:hour/' do
|
32
|
+
# Reset filter
|
35
33
|
filter = Wackamole::SearchFilter.new
|
36
34
|
filter.mole_type( params[:type].to_i )
|
37
|
-
|
35
|
+
filter.hour = params[:hour].to_i
|
38
36
|
session[:filter] = filter
|
37
|
+
|
39
38
|
redirect '/logs/1'
|
40
39
|
end
|
41
40
|
|
41
|
+
# ---------------------------------------------------------------------------
|
42
|
+
get '/dashboard/users/:hour/' do
|
43
|
+
# Reset filter
|
44
|
+
filter = Wackamole::SearchFilter.new
|
45
|
+
filter.hour = params[:hour].to_i
|
46
|
+
session[:filter] = filter
|
47
|
+
|
48
|
+
redirect '/users/1'
|
49
|
+
end
|
42
50
|
end
|
data/lib/controllers/features.rb
CHANGED
@@ -3,10 +3,7 @@ module Features
|
|
3
3
|
# ---------------------------------------------------------------------------
|
4
4
|
# paginate top features
|
5
5
|
get "/features/:page" do
|
6
|
-
page
|
7
|
-
|
8
|
-
puts @filter.inspect
|
9
|
-
|
6
|
+
page = params[:page] ? params[:page].to_i : 1
|
10
7
|
@features = Wackamole::Feature.paginate_tops( @filter.to_conds, page )
|
11
8
|
@search_path = "/features/search"
|
12
9
|
@filter_path = "/features/filter"
|
@@ -38,7 +35,6 @@ puts @filter.inspect
|
|
38
35
|
post "/features/filter" do
|
39
36
|
@filter.from_options( params[:filter] )
|
40
37
|
session[:filter] = @filter
|
41
|
-
puts "Setting #{session[:filter].inspect}"
|
42
38
|
@features = Wackamole::Feature.paginate_tops( @filter.to_conds )
|
43
39
|
erb :"features/filter.js", :layout => false
|
44
40
|
end
|
data/lib/controllers/logs.rb
CHANGED
@@ -21,7 +21,7 @@ module Logs
|
|
21
21
|
@filter.search_terms = params[:search_filter][:search_terms]
|
22
22
|
@logs = Wackamole::Log.paginate( @filter.to_conds )
|
23
23
|
rescue => boom
|
24
|
-
puts boom
|
24
|
+
# puts boom
|
25
25
|
flash_it!( :error, boom )
|
26
26
|
@logs = [].paginate
|
27
27
|
end
|
@@ -43,16 +43,7 @@ module Logs
|
|
43
43
|
@filter.from_options( params[:filter] )
|
44
44
|
session[:filter] = @filter
|
45
45
|
|
46
|
-
|
47
|
-
|
48
|
-
# end
|
49
|
-
# puts "Filter logs %5.4f" % elapsed
|
50
|
-
|
51
|
-
out = nil
|
52
|
-
# elapsed = Benchmark.realtime do
|
53
|
-
out = erb :"logs/filter.js", :layout => false
|
54
|
-
# end
|
55
|
-
# puts "Render logs %5.4f" % elapsed
|
56
|
-
out
|
46
|
+
@logs = Wackamole::Log.paginate( @filter.to_conds )
|
47
|
+
erb :"logs/filter.js", :layout => false
|
57
48
|
end
|
58
49
|
end
|
data/lib/controllers/mission.rb
CHANGED
@@ -26,6 +26,21 @@ module Mission
|
|
26
26
|
erb :'/mission/refresh_js', :layout => false
|
27
27
|
end
|
28
28
|
|
29
|
+
get '/mission/logs/:app_name/:stage/:type' do
|
30
|
+
Wackamole::Control.switch_mole_db!( params[:app_name].downcase, params[:stage] )
|
31
|
+
|
32
|
+
# Set app info
|
33
|
+
@app_info = Wackamole::Feature.get_app_info
|
34
|
+
session[:app_info] = @app_info
|
35
|
+
|
36
|
+
# Reset filter
|
37
|
+
filter = Wackamole::SearchFilter.new
|
38
|
+
filter.mole_type( params[:type].to_i )
|
39
|
+
session[:filter] = filter
|
40
|
+
|
41
|
+
redirect '/logs/1'
|
42
|
+
end
|
43
|
+
|
29
44
|
# # ---------------------------------------------------------------------------
|
30
45
|
# get '/mission/fixed/:app/:env/:type' do
|
31
46
|
# Wackamole::Mission.reset!( params[:app], params[:env], params[:type] )
|
data/lib/controllers/users.rb
CHANGED
@@ -4,12 +4,7 @@ module Users
|
|
4
4
|
# Paginate top users
|
5
5
|
get "/users/:page" do
|
6
6
|
page = params[:page] ? params[:page].to_i : 1
|
7
|
-
|
8
|
-
puts "User filter", @filter.inspect
|
9
|
-
elapsed = Benchmark.realtime do
|
10
|
-
@users = Wackamole::User.paginate_tops( @filter.to_conds, page )
|
11
|
-
end
|
12
|
-
puts "Find users %5.4f" % elapsed
|
7
|
+
@users = Wackamole::User.paginate_tops( @filter.to_conds, page )
|
13
8
|
|
14
9
|
@search_path = "/users/search"
|
15
10
|
@filter_path = "/users/filter"
|
@@ -41,7 +36,6 @@ puts "Find users %5.4f" % elapsed
|
|
41
36
|
post "/users/filter" do
|
42
37
|
@filter.from_options( params[:filter] )
|
43
38
|
session[:filter] = @filter
|
44
|
-
puts "Setting user filter #{session[:filter].inspect}"
|
45
39
|
@users = Wackamole::User.paginate_tops( @filter.to_conds )
|
46
40
|
erb :"users/filter.js", :layout => false
|
47
41
|
end
|
@@ -15,10 +15,7 @@ module MissionHelper
|
|
15
15
|
last_tick = last_tick || Chronic.parse( '1 minute ago' )
|
16
16
|
session[:last_tick] = Time.now
|
17
17
|
|
18
|
-
|
19
|
-
@reports = Wackamole::Mission.rollups( last_tick.utc, reset )
|
20
|
-
end
|
21
|
-
puts "Rollups %5.4f" % elapsed
|
18
|
+
@reports = Wackamole::Mission.rollups( last_tick.utc, reset )
|
22
19
|
end
|
23
20
|
|
24
21
|
# -------------------------------------------------------------------------
|
@@ -31,27 +31,25 @@ module Wackamole
|
|
31
31
|
def self.count_logs( now=nil, single_day=false )
|
32
32
|
counts = {}
|
33
33
|
conds = gen_conds( now, single_day )
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
end
|
46
|
-
row = counts[app_name][env]
|
47
|
-
[Rackamole.feature, Rackamole.perf, Rackamole.fault].each do |t|
|
48
|
-
conds[:typ] = t
|
49
|
-
logs = logs_cltn.find( conds, :fields => [:_id] )
|
50
|
-
row[t] = logs.count
|
51
|
-
end
|
34
|
+
|
35
|
+
Wackamole::Control.mole_databases.each do |db_name|
|
36
|
+
db = Wackamole::Control.db( db_name )
|
37
|
+
app_name, env = Wackamole::Control.extract_app_info( db_name )
|
38
|
+
logs_cltn = db['logs']
|
39
|
+
|
40
|
+
totals = { Rackamole.feature => 0, Rackamole.perf => 0, Rackamole.fault => 0 }
|
41
|
+
if counts[app_name]
|
42
|
+
counts[app_name][env] = totals
|
43
|
+
else
|
44
|
+
counts[app_name] = { env => totals }
|
52
45
|
end
|
53
|
-
|
54
|
-
|
46
|
+
row = counts[app_name][env]
|
47
|
+
[Rackamole.feature, Rackamole.perf, Rackamole.fault].each do |t|
|
48
|
+
conds[:typ] = t
|
49
|
+
logs = logs_cltn.find( conds, :fields => [:_id] )
|
50
|
+
row[t] = logs.count
|
51
|
+
end
|
52
|
+
end
|
55
53
|
counts
|
56
54
|
end
|
57
55
|
|
@@ -12,52 +12,40 @@ module Wackamole
|
|
12
12
|
# TODO - PERF - try just using cursor vs to_a
|
13
13
|
def self.collect_dashboard_info( now )
|
14
14
|
info = {}
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
|
16
|
+
info[:total_users] = users_cltn.count
|
17
|
+
info[:total_features] = features_cltn.count
|
18
|
+
info[:perf_load] = 0
|
19
|
+
info[:fault_load] = 0
|
18
20
|
|
19
|
-
# Fetch
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
end
|
24
|
-
info[:total_users] = users_cltn.count
|
25
|
-
info[:user_load] = users.size
|
21
|
+
# Fetch day logs
|
22
|
+
day_logs = logs_cltn.find( { :did => now.utc.to_date_id.to_s },
|
23
|
+
:fields => [:typ, :fid, :tid, :did, :uid],
|
24
|
+
:sort => [ [:tid => Mongo::ASCENDING] ] )
|
26
25
|
|
27
|
-
# Fetch features for this hour
|
28
|
-
features = day_logs.inject( Set.new ) do |set,log|
|
29
|
-
set << log['fid'].to_s if log['tid'] =~ /^#{"%02d" % now.hour}/
|
30
|
-
set
|
31
|
-
end
|
32
|
-
info[:total_features] = features_cltn.count
|
33
|
-
info[:feature_load] = features.size
|
34
|
-
|
35
|
-
info[:perf_load] = day_logs.inject(0) do |count,log|
|
36
|
-
if log['tid'] =~ /^#{"%02d" % now.hour}/
|
37
|
-
count += (log['typ'] == Rackamole.perf ? 1 : 0 )
|
38
|
-
end
|
39
|
-
count
|
40
|
-
end
|
41
|
-
info[:fault_load] = day_logs.inject(0) do |count,log|
|
42
|
-
if log['tid'] =~ /^#{"%02d" % now.hour}/
|
43
|
-
count += (log['typ'] == Rackamole.fault ? 1 : 0 )
|
44
|
-
end
|
45
|
-
count
|
46
|
-
end
|
47
|
-
|
48
26
|
# Count all logs per hourly time period
|
27
|
+
users = Set.new
|
28
|
+
features = Set.new
|
29
|
+
local_time = now.clone.localtime
|
49
30
|
hours = (0...24).to_a
|
50
31
|
hour_info = hours.inject(OrderedHash.new) { |res,hour| res[hour] = { :user => 0, :feature => 0, :perf => 0, :fault => 0 };res }
|
51
32
|
user_per_hour = {}
|
52
33
|
day_logs.each do |log|
|
53
34
|
date_tokens = log['did'].match( /(\d{4})(\d{2})(\d{2})/ ).captures
|
54
|
-
time_tokens = log['tid'].match( /(\d{2})(\d{2})(\d{2})/ ).captures
|
55
|
-
|
56
|
-
|
57
|
-
local = utc.localtime
|
35
|
+
time_tokens = log['tid'].match( /(\d{2})(\d{2})(\d{2})/ ).captures
|
36
|
+
log_utc = Time.utc( date_tokens[0], date_tokens[1], date_tokens[2], time_tokens[0], time_tokens[1], time_tokens[2] )
|
37
|
+
local = log_utc.clone.localtime
|
58
38
|
hour = local.hour
|
59
|
-
|
60
|
-
next if
|
39
|
+
|
40
|
+
next if hour > local_time.hour
|
41
|
+
|
42
|
+
if log_utc.hour == now.hour
|
43
|
+
users << log['uid']
|
44
|
+
features << log['fid']
|
45
|
+
info[:fault_load] += 1 if log['typ'] == Rackamole.fault
|
46
|
+
info[:perf_load] += 1 if log['typ'] == Rackamole.perf
|
47
|
+
end
|
48
|
+
|
61
49
|
if user_per_hour[hour]
|
62
50
|
unless user_per_hour[hour].include? log['uid']
|
63
51
|
hour_info[hour][:user] += 1
|
@@ -68,33 +56,22 @@ module Wackamole
|
|
68
56
|
hour_info[hour][:user] += 1
|
69
57
|
end
|
70
58
|
case log['typ']
|
71
|
-
when Rackamole.feature : hour_info[hour][:feature] += 1
|
59
|
+
when Rackamole.feature : hour_info[hour][:feature] += 1
|
72
60
|
when Rackamole.perf : hour_info[hour][:perf] += 1
|
73
61
|
when Rackamole.fault : hour_info[hour][:fault] += 1
|
74
62
|
end
|
75
63
|
end
|
76
|
-
|
77
|
-
|
78
|
-
info[:
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
info[:perf_series] << hash[:perf]
|
86
|
-
info[:feature_series] << hash[:feature]
|
64
|
+
|
65
|
+
info[:user_load] = users.size
|
66
|
+
info[:feature_load] = features.size
|
67
|
+
%w(user fault perf feature).each do |s|
|
68
|
+
k = "#{s}_series".to_sym
|
69
|
+
info[k] = []
|
70
|
+
hour_info.values.map do |hash|
|
71
|
+
info[k] << hash[s.to_sym]
|
72
|
+
end
|
87
73
|
end
|
88
74
|
info
|
89
|
-
end
|
90
|
-
|
91
|
-
# ===========================================================================
|
92
|
-
private
|
93
|
-
|
94
|
-
# -------------------------------------------------------------------------
|
95
|
-
# Makes sure we have some indexes set
|
96
|
-
# BOZO !! Create script to set these up ?
|
97
|
-
def self.ensure_indexes
|
98
|
-
end
|
75
|
+
end
|
99
76
|
end
|
100
77
|
end
|
@@ -3,7 +3,7 @@ require 'chronic'
|
|
3
3
|
module Wackamole
|
4
4
|
class SearchFilter
|
5
5
|
|
6
|
-
attr_accessor :time_frame, :feature_id, :type, :browser_type, :search_terms
|
6
|
+
attr_accessor :time_frame, :feature_id, :type, :browser_type, :search_terms, :hour
|
7
7
|
|
8
8
|
# ---------------------------------------------------------------------------
|
9
9
|
# Ctor
|
@@ -18,6 +18,7 @@ module Wackamole
|
|
18
18
|
@time_frame = SearchFilter.time_frames.first
|
19
19
|
@browser_type = SearchFilter.browser_types.first
|
20
20
|
@type = SearchFilter.mole_types.first
|
21
|
+
@hour = SearchFilter.hourlies.first
|
21
22
|
@search_terms = ""
|
22
23
|
end
|
23
24
|
|
@@ -33,6 +34,12 @@ module Wackamole
|
|
33
34
|
@time_frames ||= ['today', '2 days', '1 week', '2 weeks', '1 month', '3 months', '6 months', '1 year' ]
|
34
35
|
end
|
35
36
|
|
37
|
+
# ---------------------------------------------------------------------------
|
38
|
+
# Available hours
|
39
|
+
def self.hourlies
|
40
|
+
@hourlies ||= ['all'] + (1..23).to_a
|
41
|
+
end
|
42
|
+
|
36
43
|
# ---------------------------------------------------------------------------
|
37
44
|
# Collection of mole types
|
38
45
|
def self.mole_types
|
@@ -107,7 +114,6 @@ module Wackamole
|
|
107
114
|
def from_options( options )
|
108
115
|
return unless options
|
109
116
|
options.each_pair do |k,v|
|
110
|
-
# value = k.index( /_id$/) ? v.to_i : v
|
111
117
|
self.send( "#{k}=", v )
|
112
118
|
end
|
113
119
|
end
|
@@ -135,6 +141,13 @@ module Wackamole
|
|
135
141
|
time = Chronic.parse( time_frame + ( time_frame == SearchFilter.time_frames.first ? "" : " ago" ) )
|
136
142
|
conds[:did] = { '$gte' => time.to_date_id.to_s }
|
137
143
|
|
144
|
+
unless self.hour == 'all'
|
145
|
+
now = Time.now
|
146
|
+
current = "%4d/%02d/%02d %02d:%02d:%02d" % [now.year, now.month, now.day, self.hour, 0, 0]
|
147
|
+
time = Chronic.parse( current ).utc
|
148
|
+
conds[:tid] = /^#{"%02d"%time.hour}.+/
|
149
|
+
end
|
150
|
+
|
138
151
|
unless search_terms.empty?
|
139
152
|
tokens = search_terms.split( ":" ).collect{ |c| c.strip }
|
140
153
|
key = tokens.shift
|
data/lib/wackamole.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Wackamole
|
2
2
|
|
3
3
|
# :stopdoc:
|
4
|
-
VERSION = '0.0.
|
4
|
+
VERSION = '0.0.7' unless defined? Wackamole::VERSION
|
5
5
|
LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR unless defined? Wackamole::LIBPATH
|
6
6
|
PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR unless defined? Wackamole::PATH
|
7
7
|
# :startdoc:
|
@@ -17,12 +17,53 @@ function truncate(str, limit)
|
|
17
17
|
return bits.join('');
|
18
18
|
}
|
19
19
|
|
20
|
-
|
21
|
-
function
|
20
|
+
// Graphs...
|
21
|
+
function gen_load( name, value, total )
|
22
22
|
{
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
23
|
+
var p = Raphael( name, 300, 20 );
|
24
|
+
var range = Math.ceil( ((value/total)*100)/10 );
|
25
|
+
var x = 2;
|
26
|
+
var y = 2;
|
27
|
+
var spacer = 5;
|
28
|
+
|
29
|
+
for( var i=1; i <= range; i++ )
|
30
|
+
{
|
31
|
+
var l = p.rect( x, y, 10, 16, 2 );
|
32
|
+
l.attr( 'fill', 'green' );
|
33
|
+
l.attr( 'gradient', '45-#0f0-#fff' );
|
34
|
+
l.attr( 'stroke-width', 0 );
|
35
|
+
x += 10 + spacer;
|
36
|
+
|
37
|
+
}
|
38
|
+
var text = p.text( 230, 10, Math.ceil((value/total)*100) + '% (' + value + " of " + total + ')' );
|
39
|
+
text.attr( 'fill' , '#434343' );
|
40
|
+
text.attr( 'font-size', 15 );
|
28
41
|
}
|
42
|
+
|
43
|
+
function gen_heat_map( url, id, series, symbol, xs, ys, axisx, axisy )
|
44
|
+
{
|
45
|
+
var r = Raphael( id );
|
46
|
+
var urls = [];
|
47
|
+
|
48
|
+
for( hour in xs ) {
|
49
|
+
var u = url + hour + "/";
|
50
|
+
urls[hour] = u;
|
51
|
+
}
|
52
|
+
|
53
|
+
var chart = r.g.dotchart(0, -10, 620, 60, xs, ys, series, {href: urls, symbol: symbol, max: 10, heat: true, axis: "0 0 1 0", axisxstep: 23, axisystep: 1, axisxlabels: axisx, axisxtype: " ", axisytype: " ", axisylabels: axisy})
|
54
|
+
|
55
|
+
chart.hover( function () {
|
56
|
+
this.tag = this.tag || r.g.tag(this.x, this.y, this.value, 0, this.r + 2).insertBefore(this);
|
57
|
+
this.tag.show();
|
58
|
+
},
|
59
|
+
function () {
|
60
|
+
this.tag && this.tag.hide();
|
61
|
+
}
|
62
|
+
);
|
63
|
+
|
64
|
+
chart.click( function() {
|
65
|
+
// this.tag = this.tag || r.g.tag(this.x, this.y, this.value, 0, this.r + 2).insertBefore(this);
|
66
|
+
// console.log( "Clicked url " + this.href );
|
67
|
+
// return false;
|
68
|
+
})
|
69
|
+
}
|
@@ -549,16 +549,16 @@ ul#summary li p{
|
|
549
549
|
|
550
550
|
|
551
551
|
p#perfs {
|
552
|
-
background: transparent url(/images/perf_small.png) no-repeat
|
552
|
+
background: transparent url(/images/perf_small.png) no-repeat 1px 2px;
|
553
553
|
}
|
554
554
|
p#faults {
|
555
|
-
background: transparent url(/images/fault_small.png) no-repeat
|
555
|
+
background: transparent url(/images/fault_small.png) no-repeat 1px 2px;
|
556
556
|
}
|
557
557
|
p#users {
|
558
|
-
background: transparent url(/images/users.png) no-repeat
|
558
|
+
background: transparent url(/images/users.png) no-repeat 1px 2px;
|
559
559
|
}
|
560
560
|
p#features {
|
561
|
-
background: transparent url(/images/feature.png) no-repeat
|
561
|
+
background: transparent url(/images/feature.png) no-repeat 1px 2px;
|
562
562
|
}
|
563
563
|
|
564
564
|
div.section ul li p.result {
|
@@ -6,7 +6,7 @@ describe Wackamole::MoledInfo do
|
|
6
6
|
Wackamole::Control.init_config( File.join(File.dirname(__FILE__), %w[.. config test.yml]), 'test' )
|
7
7
|
Wackamole::Control.connection.should_not be_nil
|
8
8
|
Wackamole::Control.db( "mole_fred_test_mdb" )
|
9
|
-
@test_time = Chronic.parse( "2010/01/01 01:00:00" )
|
9
|
+
@test_time = Chronic.parse( "2010/01/01 01:00:00" )
|
10
10
|
end
|
11
11
|
|
12
12
|
it "should gather dashboard info correctly" do
|
data/views/dashboard/_report.erb
CHANGED
@@ -10,11 +10,23 @@
|
|
10
10
|
<div id="feature_load" class="load"></div>
|
11
11
|
<li>
|
12
12
|
<p class="status">Performance</p>
|
13
|
-
<p class="result"
|
13
|
+
<p class="result">
|
14
|
+
<% if @info[:perf_load] > 0 %>
|
15
|
+
<%= link_to pluralize( @info[:perf_load], 'issue' ), "/dashboard/logs/#{Rackamole.perf}/", :class => "site_link" %>
|
16
|
+
<% else %>
|
17
|
+
<%=pluralize( @info[:perf_load], 'issue' )%>
|
18
|
+
<% end %>
|
19
|
+
</p>
|
14
20
|
</li>
|
15
21
|
<li>
|
16
22
|
<p class="status">Uncaught Exceptions</p>
|
17
|
-
<p class="result"
|
23
|
+
<p class="result">
|
24
|
+
<% if @info[:fault_load] > 0 %>
|
25
|
+
<%= link_to pluralize( @info[:fault_load], 'issue' ), "/dashboard/logs/#{Rackamole.fault}/", :class => "site_link" %>
|
26
|
+
<% else %>
|
27
|
+
<%=pluralize( @info[:fault_load], 'issue' )%>
|
28
|
+
<% end %>
|
29
|
+
</p>
|
18
30
|
</li>
|
19
31
|
</ul>
|
20
32
|
</div>
|
@@ -47,72 +59,43 @@
|
|
47
59
|
<% end %>
|
48
60
|
</li>
|
49
61
|
<li>
|
50
|
-
<p id="features">
|
62
|
+
<p id="features">Logs</p>
|
51
63
|
<% unless zeroed_series?( @info[:feature_series] ) %>
|
52
64
|
<div class="heat" id="svg_features"></div>
|
53
65
|
<% else %>
|
54
|
-
<p class="no_report">No
|
66
|
+
<p class="no_report">No Logs reported.</p>
|
55
67
|
<% end %>
|
56
68
|
</li>
|
57
69
|
</ul>
|
58
70
|
</div>
|
59
71
|
|
60
|
-
<script>
|
61
|
-
function
|
62
|
-
|
63
|
-
|
64
|
-
var
|
65
|
-
var x = 2;
|
66
|
-
var y = 2;
|
67
|
-
var spacer = 5;
|
68
|
-
|
69
|
-
for( var i=1; i <= range; i++ )
|
70
|
-
{
|
71
|
-
var l = p.rect( x, y, 10, 16, 2 );
|
72
|
-
l.attr( 'fill', 'green' );
|
73
|
-
l.attr( 'gradient', '45-#0f0-#fff' );
|
74
|
-
l.attr( 'stroke-width', 0 );
|
75
|
-
x += 10 + spacer;
|
76
|
-
|
77
|
-
}
|
78
|
-
var text = p.text( 230, 10, Math.ceil((value/total)*100) + '% (' + value + " of " + total + ')' );
|
79
|
-
text.attr( 'fill' , '#434343' );
|
80
|
-
text.attr( 'font-size', 15 );
|
81
|
-
}
|
82
|
-
|
83
|
-
function gen_heat_map( id, series, symbol )
|
84
|
-
{
|
85
|
-
var r = Raphael( id ),
|
86
|
-
xs = <%= (0..23).to_a.to_json %>,
|
72
|
+
<script>
|
73
|
+
$( function() {
|
74
|
+
$('a.dash').addClass( 'current' );
|
75
|
+
|
76
|
+
var xs = <%= (0..23).to_a.to_json %>,
|
87
77
|
ys = <%= y = [];24.times{ y << 1 };y.to_json %>,
|
88
78
|
axisy = <%= %w[Mon].to_json %>,
|
89
79
|
axisx = <%= %w[12am 1 2 3 4 5 6 7 8 9 10 11 12 1 2 3 4 5 6 7 8 9 10 11].to_json %>;
|
90
|
-
|
91
|
-
r.g.dotchart(0, -10, 620, 60, xs, ys, series, {symbol: symbol, max: 10, heat: true, axis: "0 0 1 0", axisxstep: 23, axisystep: 1, axisxlabels: axisx, axisxtype: " ", axisytype: " ", axisylabels: axisy}).hover(function () {
|
92
|
-
this.tag = this.tag || r.g.tag(this.x, this.y, this.value, 0, this.r + 2).insertBefore(this);
|
93
|
-
this.tag.show();
|
94
|
-
}, function () {
|
95
|
-
this.tag && this.tag.hide();
|
96
|
-
});
|
97
|
-
}
|
98
|
-
|
99
|
-
$( function() {
|
100
|
-
$('a.dash').addClass( 'current' );
|
101
80
|
|
102
81
|
gen_load( 'user_load' , <%=@info[:user_load]%>, <%=@info[:total_users]%> );
|
103
82
|
gen_load( 'feature_load', <%=@info[:feature_load]%>, <%=@info[:total_features]%> );
|
104
|
-
|
83
|
+
|
105
84
|
<% unless zeroed_series?( @info[:fault_series] ) %>
|
106
|
-
|
85
|
+
var url = "/dashboard/logs/<%=Rackamole.fault%>/";
|
86
|
+
gen_heat_map( url, 'svg_faults', <%=@info[:fault_series].to_json%>, 'cross' , xs, ys, axisx, axisy );
|
107
87
|
<% end %>
|
108
88
|
<% unless zeroed_series?( @info[:perf_series] ) %>
|
109
|
-
|
89
|
+
var url = "/dashboard/logs/<%=Rackamole.perf%>/";
|
90
|
+
gen_heat_map( url, 'svg_perf', <%=@info[:perf_series].to_json%>, 'diamond', xs, ys, axisx, axisy );
|
110
91
|
<% end %>
|
111
92
|
<% unless zeroed_series?( @info[:user_series] ) %>
|
112
|
-
|
93
|
+
var url = "/dashboard/users/";
|
94
|
+
gen_heat_map( url, 'svg_users', <%=@info[:user_series].to_json%>, 'disc', xs, ys, axisx, axisy );
|
113
95
|
<% end %>
|
114
|
-
<% unless zeroed_series?( @info[:
|
115
|
-
|
96
|
+
<% unless zeroed_series?( @info[:feature_series] ) %>
|
97
|
+
var url = "/dashboard/logs/<%=Rackamole.feature%>/";
|
98
|
+
gen_heat_map( url, 'svg_features', <%=@info[:feature_series].to_json%>, 'flower', xs, ys, axisx, axisy );
|
116
99
|
<% end %>
|
117
100
|
});
|
118
101
|
</script>
|
data/views/dashboard/index.erb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
-
$('
|
1
|
+
$('span#timestamp').html( "<%=escape_javascript(partial(:'shared/timestamp'))%>" );
|
2
|
+
$("span#timestamp").effect( 'pulsate', { times:1 }, 500 );
|
2
3
|
|
3
4
|
$('div#dash').html( "<%=escape_javascript(partial(:'dashboard/report'))%>" );
|
data/views/mission/_report.erb
CHANGED
@@ -28,7 +28,7 @@ table#mission tr.div {
|
|
28
28
|
<th width="25%">application</th>
|
29
29
|
<th width="10%">environment</th>
|
30
30
|
<th width="20%">to date</th>
|
31
|
-
<th width="20%">
|
31
|
+
<th width="20%">24 hours</th>
|
32
32
|
<th width="20%">last tick</th>
|
33
33
|
</tr>
|
34
34
|
</thead>
|
@@ -48,7 +48,7 @@ table#mission tr.div {
|
|
48
48
|
<% clazz = ( (count > 0 and %w(last_tick today).include?(period)) ? assign_class( type, count ) : nil) %>
|
49
49
|
<td width="25px">
|
50
50
|
<% if( %w(last_tick today).include?( period ) and count > 0 ) %>
|
51
|
-
<%= link_to Wackamole::Mission.to_type_name(type), "/
|
51
|
+
<%= link_to Wackamole::Mission.to_type_name(type), "/mission/logs/#{app_name}/#{env}/#{type}", :class => "site_link" %>:
|
52
52
|
<% else %>
|
53
53
|
<%=Wackamole::Mission.to_type_name(type)%>:
|
54
54
|
<% end %>
|
data/views/shared/_filter.erb
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
<div id="filters" class="corners">
|
2
2
|
<form id="filter_form">
|
3
|
+
<fieldset id="submit">
|
4
|
+
<label>
|
5
|
+
|
6
|
+
<input type="submit" name="commit" value="Filter"/>
|
7
|
+
<%= image_tag 'loading.gif', :border => '0', :size => '24x24', :id => 'loading' %>
|
8
|
+
</label>
|
9
|
+
</fieldset>
|
10
|
+
|
3
11
|
<fieldset class="inline">
|
4
12
|
<label for="time_frame">
|
5
13
|
Time range:
|
@@ -9,6 +17,15 @@
|
|
9
17
|
</label>
|
10
18
|
</fieldset>
|
11
19
|
|
20
|
+
<fieldset class="inline">
|
21
|
+
<label for="hourly_frame">
|
22
|
+
Hour of Day:
|
23
|
+
<select id="hourly_frame" name="filter[hour]">
|
24
|
+
<%= options_for_select Wackamole::SearchFilter.hourlies, @filter.hour %>
|
25
|
+
</select>
|
26
|
+
</label>
|
27
|
+
</fieldset>
|
28
|
+
|
12
29
|
<fieldset class="inline">
|
13
30
|
<label for="type">
|
14
31
|
Type:
|
@@ -35,13 +52,6 @@
|
|
35
52
|
</select>
|
36
53
|
</label>
|
37
54
|
</fieldset>
|
38
|
-
<fieldset id="submit">
|
39
|
-
<label>
|
40
|
-
|
41
|
-
<input type="submit" name="commit" value="Filter"/>
|
42
|
-
<%= image_tag 'loading.gif', :border => '0', :size => '24x24', :id => 'loading' %>
|
43
|
-
</label>
|
44
|
-
</fieldset>
|
45
55
|
</form>
|
46
56
|
</div>
|
47
57
|
|
data/views/shared/_timestamp.erb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
<%= @updated_on.strftime( "%m/%d/%y %H:%M:%S") %>
|
1
|
+
<%= @updated_on.clone.localtime.strftime( "%m/%d/%y %H:%M:%S") %>
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wackamole
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
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: 2010-02-
|
12
|
+
date: 2010-02-21 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|