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.
- data/.bnsignore +16 -0
- data/.gitignore +2 -0
- data/History.txt +4 -0
- data/README.rdoc +88 -0
- data/Rakefile +42 -0
- data/aa.rb +25 -0
- data/aaa.txt +13 -0
- data/bin/wackamole +77 -0
- data/lib/app.rb +63 -0
- data/lib/controllers/dashboard.rb +30 -0
- data/lib/controllers/features.rb +41 -0
- data/lib/controllers/logs.rb +49 -0
- data/lib/controllers/mission.rb +27 -0
- data/lib/controllers/users.rb +41 -0
- data/lib/helpers/dashboard_helper.rb +32 -0
- data/lib/helpers/features_helper.rb +13 -0
- data/lib/helpers/flash_helper.rb +16 -0
- data/lib/helpers/logs_helper.rb +116 -0
- data/lib/helpers/main_helper.rb +182 -0
- data/lib/helpers/mission_helper.rb +59 -0
- data/lib/helpers/rails_helper.rb +7 -0
- data/lib/wackamole.rb +47 -0
- data/lib/wackamole/core_ext/date_time.rb +8 -0
- data/lib/wackamole/core_ext/time.rb +9 -0
- data/lib/wackamole/models/control.rb +132 -0
- data/lib/wackamole/models/feature.rb +74 -0
- data/lib/wackamole/models/log.rb +45 -0
- data/lib/wackamole/models/mission.rb +164 -0
- data/lib/wackamole/models/mole_info.rb +94 -0
- data/lib/wackamole/models/search_filter.rb +192 -0
- data/lib/wackamole/models/user.rb +46 -0
- data/public/favicon.ico +0 -0
- data/public/images/.DS_Store +0 -0
- data/public/images/browsers/.DS_Store +0 -0
- data/public/images/browsers/MSIE 6.png +0 -0
- data/public/images/browsers/MSIE 8.0 +0 -0
- data/public/images/browsers/MSIE 8.0.png +0 -0
- data/public/images/browsers/chrome.png +0 -0
- data/public/images/browsers/firefox.png +0 -0
- data/public/images/browsers/ie 6.0.png +0 -0
- data/public/images/browsers/ie6.jpg +0 -0
- data/public/images/browsers/ie7.jpg +0 -0
- data/public/images/browsers/ie7.png +0 -0
- data/public/images/browsers/msie 6.0.png +0 -0
- data/public/images/browsers/msie 7.0.png +0 -0
- data/public/images/browsers/opera.jpg +0 -0
- data/public/images/browsers/opera.png +0 -0
- data/public/images/browsers/safari.jpg +0 -0
- data/public/images/browsers/safari.png +0 -0
- data/public/images/browsers/unknown_browser.png +0 -0
- data/public/images/close.png +0 -0
- data/public/images/error.png +0 -0
- data/public/images/fade.png +0 -0
- data/public/images/fault_big.png +0 -0
- data/public/images/fault_small.png +0 -0
- data/public/images/feature.png +0 -0
- data/public/images/h300.png +0 -0
- data/public/images/hori_large.png +0 -0
- data/public/images/info_big.png +0 -0
- data/public/images/info_small.png +0 -0
- data/public/images/loading.gif +0 -0
- data/public/images/loading1.gif +0 -0
- data/public/images/mole_error.png +0 -0
- data/public/images/more.gif +0 -0
- data/public/images/next.png +0 -0
- data/public/images/perf_big.png +0 -0
- data/public/images/perf_small.png +0 -0
- data/public/images/powered_by.png +0 -0
- data/public/images/prev.png +0 -0
- data/public/images/row_fade.png +0 -0
- data/public/images/search.png +0 -0
- data/public/images/small_logo.png +0 -0
- data/public/images/spaceball.gif +0 -0
- data/public/images/tick.png +0 -0
- data/public/images/users.png +0 -0
- data/public/images/wackamole_logo.png +0 -0
- data/public/javascripts/.DS_Store +0 -0
- data/public/javascripts/application.js +28 -0
- data/public/javascripts/g.dot.min.js +7 -0
- data/public/javascripts/g.raphael.min.js +7 -0
- data/public/javascripts/jit.js +9052 -0
- data/public/javascripts/jit.min.js +1 -0
- data/public/javascripts/jquery-ui.js +188 -0
- data/public/javascripts/jquery.example.js +160 -0
- data/public/javascripts/jquery.js +19 -0
- data/public/javascripts/jquery.tools.min.js +38 -0
- data/public/javascripts/jquery_ba-url.js +9 -0
- data/public/javascripts/jquery_min.js +19 -0
- data/public/javascripts/jquery_ui_min.js +298 -0
- data/public/javascripts/raphael.min.js +7 -0
- data/public/stylesheets/tabs-slideshow.css +95 -0
- data/public/stylesheets/wackamole.css +684 -0
- data/spec/config/bogus_test.yml +3 -0
- data/spec/config/test.yml +3 -0
- data/spec/core_ext/date_time_spec.rb +8 -0
- data/spec/core_ext/time_spec.rb +12 -0
- data/spec/data/fixtures.rb +92 -0
- data/spec/models/control_spec.rb +98 -0
- data/spec/models/feature_spec.rb +52 -0
- data/spec/models/log_spec.rb +43 -0
- data/spec/models/mission_spec.rb +225 -0
- data/spec/models/moled_info_spec.rb +30 -0
- data/spec/models/search_filter_spec.rb +151 -0
- data/spec/models/user_spec.rb +44 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/wackamole_spec.rb +20 -0
- data/tasks/bones.rake +20 -0
- data/tasks/fixtures.rake +13 -0
- data/tasks/gem.rake +201 -0
- data/tasks/git.rake +40 -0
- data/tasks/notes.rake +27 -0
- data/tasks/post_load.rake +32 -0
- data/tasks/rdoc.rake +54 -0
- data/tasks/rubyforge.rake +55 -0
- data/tasks/setup.rb +290 -0
- data/tasks/spec.rake +54 -0
- data/tasks/svn.rake +46 -0
- data/views/dashboard/_report.erb +118 -0
- data/views/dashboard/index.erb +4 -0
- data/views/dashboard/refresh_js.erb +3 -0
- data/views/features/_rows.erb +26 -0
- data/views/features/filter.js.erb +2 -0
- data/views/features/index.erb +24 -0
- data/views/features/index.js.erb +2 -0
- data/views/layout.erb +47 -0
- data/views/logs/_array.erb +12 -0
- data/views/logs/_hash.erb +14 -0
- data/views/logs/_rows.erb +65 -0
- data/views/logs/filter.js.erb +4 -0
- data/views/logs/index.erb +13 -0
- data/views/logs/index.js.erb +2 -0
- data/views/logs/show.erb +66 -0
- data/views/mission/_report.erb +49 -0
- data/views/mission/index.erb +7 -0
- data/views/mission/refresh_js.erb +3 -0
- data/views/shared/_filter.erb +63 -0
- data/views/shared/_flash.erb +3 -0
- data/views/shared/_search.erb +25 -0
- data/views/shared/_timestamp.erb +1 -0
- data/views/shared/_wait.erb +1 -0
- data/views/shared/flash.js.erb +10 -0
- data/views/users/_rows.erb +26 -0
- data/views/users/filter.js.erb +4 -0
- data/views/users/index.erb +24 -0
- data/views/users/index.js.erb +2 -0
- metadata +347 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require 'chronic'
|
|
2
|
+
|
|
3
|
+
module Mission
|
|
4
|
+
|
|
5
|
+
# ---------------------------------------------------------------------------
|
|
6
|
+
get '/mission' do
|
|
7
|
+
# reset app info
|
|
8
|
+
session[:app_info] = @app_info = nil
|
|
9
|
+
|
|
10
|
+
load_report
|
|
11
|
+
erb :'mission/index'
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# ---------------------------------------------------------------------------
|
|
15
|
+
get '/mission/refresh' do
|
|
16
|
+
load_report
|
|
17
|
+
erb :'/mission/refresh_js', :layout => false
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# ---------------------------------------------------------------------------
|
|
21
|
+
get '/mission/fixed/:app/:env/:type' do
|
|
22
|
+
Wackamole::Mission.reset!( params[:app], params[:env], params[:type] )
|
|
23
|
+
load_report
|
|
24
|
+
erb :'/mission/refresh_js', :layout => false
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module Users
|
|
2
|
+
|
|
3
|
+
# ---------------------------------------------------------------------------
|
|
4
|
+
# Paginate top users
|
|
5
|
+
get "/users/:page" do
|
|
6
|
+
page = params[:page] ? params[:page].to_i : 1
|
|
7
|
+
|
|
8
|
+
@users = Wackamole::User.paginate_tops( @filter.to_conds, page )
|
|
9
|
+
@search_path = "/users/search"
|
|
10
|
+
@filter_path = "/users/filter"
|
|
11
|
+
|
|
12
|
+
if request.xhr?
|
|
13
|
+
erb :'users/index.js', :layout => false
|
|
14
|
+
else
|
|
15
|
+
erb :'users/index'
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# ---------------------------------------------------------------------------
|
|
20
|
+
# search users
|
|
21
|
+
post "/users/search" do
|
|
22
|
+
begin
|
|
23
|
+
@filter.search_terms = params[:search_filter][:search_terms]
|
|
24
|
+
@users = Wackamole::User.paginate_tops( @filter.to_conds )
|
|
25
|
+
rescue => boom
|
|
26
|
+
logger.error boom
|
|
27
|
+
flash[:error] = boom
|
|
28
|
+
@users = [].paginate
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
erb :"users/filter.js", :layout => false
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# ---------------------------------------------------------------------------
|
|
35
|
+
# Filter
|
|
36
|
+
post "/users/filter" do
|
|
37
|
+
@filter.from_options( params[:filter] )
|
|
38
|
+
@users = Wackamole::User.paginate_tops( @filter.to_conds )
|
|
39
|
+
erb :"users/filter.js", :layout => false
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module DashboardHelper
|
|
2
|
+
|
|
3
|
+
helpers do
|
|
4
|
+
|
|
5
|
+
# -------------------------------------------------------------------------
|
|
6
|
+
# Make sure all indexes are set
|
|
7
|
+
def ensure_indexes!
|
|
8
|
+
Wackamole::Log.ensure_indexes!
|
|
9
|
+
Wackamole::User.ensure_indexes!
|
|
10
|
+
Wackamole::Feature.ensure_indexes!
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# -------------------------------------------------------------------------
|
|
14
|
+
# Retrieve moled app info...
|
|
15
|
+
def load_app_info
|
|
16
|
+
@app_info = Wackamole::Feature.get_app_info
|
|
17
|
+
session[:app_info] = @app_info
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# -------------------------------------------------------------------------
|
|
21
|
+
# Loads the application details
|
|
22
|
+
def load_app_details
|
|
23
|
+
@info = Wackamole::MoledInfo.collect_dashboard_info( @updated_on.clone.utc )
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# -------------------------------------------------------------------------
|
|
27
|
+
# Check for zeroed out series...
|
|
28
|
+
def zeroed_series?( series )
|
|
29
|
+
series.inject(0) { |res, s| res + s } == 0
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module FeaturesHelper
|
|
2
|
+
|
|
3
|
+
helpers do
|
|
4
|
+
# ---------------------------------------------------------------------------
|
|
5
|
+
# Find feature context for log entry
|
|
6
|
+
def display_context( feature )
|
|
7
|
+
if feature['ctl']
|
|
8
|
+
return "#{feature['ctl']}##{feature['act']}"
|
|
9
|
+
end
|
|
10
|
+
feature['ctx']
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module FlashHelper
|
|
2
|
+
helpers do
|
|
3
|
+
|
|
4
|
+
# clear out flash object
|
|
5
|
+
def clear_it!
|
|
6
|
+
@flash = session[:flash] || OrderedHash.new
|
|
7
|
+
@flash.clear
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# add flash message
|
|
11
|
+
def flash_it!( type, msg )
|
|
12
|
+
@flash = session[:flash] || OrderedHash.new
|
|
13
|
+
@flash[type] = msg
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
module LogsHelper
|
|
2
|
+
|
|
3
|
+
helpers do
|
|
4
|
+
# ---------------------------------------------------------------------------
|
|
5
|
+
def user_name_for( user_id )
|
|
6
|
+
user = Wackamole::User.users_cltn.find_one( user_id )
|
|
7
|
+
user['una']
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# ---------------------------------------------------------------------------
|
|
11
|
+
def feature_name_for( feature_id )
|
|
12
|
+
feature = Wackamole::Feature.features_cltn.find_one( feature_id )
|
|
13
|
+
if feature['ctx']
|
|
14
|
+
return feature['ctx']
|
|
15
|
+
end
|
|
16
|
+
"#{feature['ctrl']}##{feature['act']}"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# ---------------------------------------------------------------------------
|
|
20
|
+
def human_type( type )
|
|
21
|
+
case type
|
|
22
|
+
when Rackamole.perf
|
|
23
|
+
"Performance"
|
|
24
|
+
when Rackamole.fault
|
|
25
|
+
"Exception"
|
|
26
|
+
else
|
|
27
|
+
"Feature"
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# ---------------------------------------------------------------------------
|
|
32
|
+
# Change ids to time
|
|
33
|
+
def timestamp_for( log )
|
|
34
|
+
begin
|
|
35
|
+
date_tokens = log['did'].match( /(\d{4})(\d{2})(\d{2})/ ).captures
|
|
36
|
+
time_tokens = log['tid'].match( /(\d{2})(\d{2})(\d{2})/ ).captures
|
|
37
|
+
time = Time.utc( date_tokens[0], date_tokens[1], date_tokens[2], time_tokens[0], time_tokens[1], time_tokens[2] )
|
|
38
|
+
return time.getlocal.strftime( "%m/%d/%y %H:%M:%S")
|
|
39
|
+
rescue
|
|
40
|
+
;
|
|
41
|
+
end
|
|
42
|
+
"N/A"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# ---------------------------------------------------------------------------
|
|
46
|
+
# Find feature context for log entry
|
|
47
|
+
def context_for( feature_id )
|
|
48
|
+
feature = Wackamole::Feature.features_cltn.find_one( feature_id )
|
|
49
|
+
if feature['ctl']
|
|
50
|
+
return "#{feature['ctl']}##{feature['act']}"
|
|
51
|
+
end
|
|
52
|
+
feature['ctx']
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# ---------------------------------------------------------------------------
|
|
56
|
+
# Converts mole type to big icon
|
|
57
|
+
def mole_type_icon( type )
|
|
58
|
+
case type
|
|
59
|
+
when Rackamole.perf
|
|
60
|
+
"perf_big.png"
|
|
61
|
+
when Rackamole.fault
|
|
62
|
+
"fault_big.png"
|
|
63
|
+
else
|
|
64
|
+
"info_big.png"
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# ---------------------------------------------------------------------------
|
|
69
|
+
# Converts hash to string
|
|
70
|
+
def dump_hash( hash )
|
|
71
|
+
content = []
|
|
72
|
+
hash.each_pair do |k,v|
|
|
73
|
+
content << content_tag( :span, "#{k} -> #{v}" )
|
|
74
|
+
end
|
|
75
|
+
content.join( "" )
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# ---------------------------------------------------------------------------
|
|
79
|
+
# Trim out extra host info if any
|
|
80
|
+
def format_host( host )
|
|
81
|
+
return host.split( "." ).first if host.index( /\./ )
|
|
82
|
+
host
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# ---------------------------------------------------------------------------
|
|
86
|
+
# Check if request time is available
|
|
87
|
+
def request_time( req_time )
|
|
88
|
+
begin
|
|
89
|
+
"%4.2f" % req_time
|
|
90
|
+
rescue
|
|
91
|
+
"N/A"
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# ---------------------------------------------------------------------------
|
|
96
|
+
# Change log color depending on type
|
|
97
|
+
def row_class_for( type )
|
|
98
|
+
case type
|
|
99
|
+
when Rackamole.feature
|
|
100
|
+
"feature"
|
|
101
|
+
when Rackamole.perf
|
|
102
|
+
"perf"
|
|
103
|
+
when Rackamole.fault
|
|
104
|
+
"fault"
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# ---------------------------------------------------------------------------
|
|
109
|
+
# Setup browser icon indicator
|
|
110
|
+
def browser_icon( browser )
|
|
111
|
+
img_name = browser
|
|
112
|
+
img_name = "unknown_browser" if img_name.nil? or img_name == "N/A"
|
|
113
|
+
image_tag "browsers/#{img_name.to_s.downcase.gsub( /\\/, '')}.png", :size => "20x20"
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
require 'will_paginate/view_helpers/base'
|
|
3
|
+
require 'will_paginate/view_helpers/link_renderer'
|
|
4
|
+
|
|
5
|
+
# BOZO !! Refact helpers...
|
|
6
|
+
module WillPaginate::ViewHelpers
|
|
7
|
+
class LinkRenderer
|
|
8
|
+
def url( page )
|
|
9
|
+
"#{@options[:params][:url]}/#{page}"
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
module MainHelper
|
|
15
|
+
helpers do
|
|
16
|
+
include WillPaginate::ViewHelpers::Base
|
|
17
|
+
|
|
18
|
+
def pluralize( count, name )
|
|
19
|
+
count.to_s + " " + name + (count.to_i > 1 ? "s" : "")
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def javascript_tag( code )
|
|
23
|
+
content_tag( :script, code )
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def remote_function(options)
|
|
27
|
+
jq_options = {}
|
|
28
|
+
jq_options[:beforeSend] = options[:before] if options.has_key?( :before )
|
|
29
|
+
jq_options[:complete] = options[:complete] if options.has_key?( :complete )
|
|
30
|
+
jq_options[:success] = options[:success] if options.has_key?( :success )
|
|
31
|
+
jq_options[:error] = options[:error] if options.has_key?( :error )
|
|
32
|
+
jq_options[:url] = options[:url] if options.has_key?( :url )
|
|
33
|
+
jq_options[:data] = options[:data] if options.has_key?( :data )
|
|
34
|
+
jq_options[:dataType] = options[:data_type] || 'script'
|
|
35
|
+
jq_options[:type] = options[:type] || "GET"
|
|
36
|
+
|
|
37
|
+
buff = []
|
|
38
|
+
jq_options.each_pair { |k,v| buff << "#{k}:'#{v}'" }
|
|
39
|
+
|
|
40
|
+
"$.ajax({#{buff.join( "," )}})"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def periodically_call_remote(options = {})
|
|
44
|
+
frequency = options[:frequency] || 10 # every ten seconds by default
|
|
45
|
+
code = "setInterval(function() {#{remote_function(options)}}, #{frequency} * 1000)"
|
|
46
|
+
javascript_tag(code)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def content_tag( tag, content, opts={} )
|
|
50
|
+
"<#{tag} #{html_options( opts )}>#{content}</#{tag}>"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def options_for_select( list, selection )
|
|
54
|
+
buff = []
|
|
55
|
+
list.each do |option|
|
|
56
|
+
opts = {}
|
|
57
|
+
if option.is_a? Array
|
|
58
|
+
opts[:value] = option.last
|
|
59
|
+
content = option.first
|
|
60
|
+
opts[:selected] = "selected" if option.last == selection
|
|
61
|
+
else
|
|
62
|
+
content = option
|
|
63
|
+
opts[:value] = option
|
|
64
|
+
opts[:selected] = "selected" if option == selection
|
|
65
|
+
end
|
|
66
|
+
buff << content_tag( :option, content, opts )
|
|
67
|
+
end
|
|
68
|
+
buff.join( "\n" )
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def image_tag( name, opts={} )
|
|
72
|
+
"<img src=\"/images/#{name}\" #{html_options( opts )}/>"
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def link_to_remote( name, url, opts={} )
|
|
76
|
+
"<a href=\"#\" onclick=\"#{remote_function({:url=>url})};return false;\" #{html_options(opts)}>#{name}</a>"
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# def form_remote_tag( name, opts={}, html_opts={} )
|
|
80
|
+
# "<form onsubmit=\"#{remote_function(opts)};return false;\" #{html_options(html_opts)}></form>"
|
|
81
|
+
# end
|
|
82
|
+
|
|
83
|
+
def link_to( name, url, opts={} )
|
|
84
|
+
"<a href=\"#{url}\" #{html_options(opts)}>#{name}</a>"
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def html_options( opts )
|
|
88
|
+
html = []
|
|
89
|
+
html << "id=\"#{opts[:id]}\"" if opts.has_key?( :id )
|
|
90
|
+
html << "border=\"#{opts[:border]}\"" if opts.has_key?( :border )
|
|
91
|
+
html << "class=\"#{opts[:class]}\"" if opts.has_key?( :class )
|
|
92
|
+
if opts.has_key?( :size )
|
|
93
|
+
size = opts[:size]
|
|
94
|
+
width, height = size.split( 'x' )
|
|
95
|
+
style = "width:#{width}px;height:#{height}px;"
|
|
96
|
+
if opts[:style]
|
|
97
|
+
opts[:style] += ";#{style}"
|
|
98
|
+
else
|
|
99
|
+
opts[:style] = style
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
html << "style=\"#{opts[:style]}\"" if opts.has_key?( :style )
|
|
103
|
+
html << "selected=\"selected\"" if opts.has_key?( :selected )
|
|
104
|
+
html << "value=\"#{opts[:value]}\"" if opts.has_key?( :value )
|
|
105
|
+
html.empty? ? "" : html.join( " " )
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def stylesheets( styles )
|
|
109
|
+
buff = []
|
|
110
|
+
styles.each do |style|
|
|
111
|
+
buff << "<link rel=\"stylesheet\" href=\"#{v_styles( style )}\" type=\"text/css\" media=\"screen\" />"
|
|
112
|
+
end
|
|
113
|
+
buff.join( "\n" )
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def javascripts( scripts )
|
|
117
|
+
buff = []
|
|
118
|
+
scripts.each do |script|
|
|
119
|
+
buff << "<script src=\"#{v_js( script )}\" type=\"text/javascript\"></script>"
|
|
120
|
+
end
|
|
121
|
+
buff.join( "\n" )
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def v_styles(stylesheet)
|
|
125
|
+
"/stylesheets/#{stylesheet}.css?" + File.mtime(File.join(Sinatra::Application.public, "stylesheets", "#{stylesheet}.css")).to_i.to_s
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def v_js(js)
|
|
129
|
+
"/javascripts/#{js}.js?" + File.mtime(File.join(Sinatra::Application.public, "javascripts", "#{js}.js")).to_i.to_s
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# truncate a string - won't work for multibyte
|
|
133
|
+
def truncate(text, length = 30, truncate_string = "...")
|
|
134
|
+
return "" if text.nil?
|
|
135
|
+
l = length - truncate_string.size
|
|
136
|
+
text.size > length ? (text[0...l] + truncate_string).to_s : text
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def align_for( value )
|
|
140
|
+
return "right" if value.is_a?(Fixnum)
|
|
141
|
+
"left"
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# Add thousand markers
|
|
145
|
+
def format_number( value )
|
|
146
|
+
return value.to_s.gsub(/(\d)(?=\d{3}+(\.\d*)?$)/, '\1,') if value.instance_of?(Fixnum)
|
|
147
|
+
value
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def partial( page, options={} )
|
|
151
|
+
if object = options.delete(:object)
|
|
152
|
+
template = page.to_s.split("/").last
|
|
153
|
+
options.merge!( :locals => { template.to_sym => object } )
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
if page.to_s.index( /\// )
|
|
157
|
+
page = page.to_s.gsub( /\//, '/_' )
|
|
158
|
+
else
|
|
159
|
+
page = "_" + page.to_s
|
|
160
|
+
end
|
|
161
|
+
erb page.to_sym, options.merge!( :layout => false )
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
JS_ESCAPE_MAP =
|
|
165
|
+
{
|
|
166
|
+
'\\' => '\\\\',
|
|
167
|
+
'</' => '<\/',
|
|
168
|
+
"\r\n" => '\n',
|
|
169
|
+
"\n" => '\n',
|
|
170
|
+
"\r" => '\n',
|
|
171
|
+
'"' => '\\"',
|
|
172
|
+
"'" => "\\'"
|
|
173
|
+
}
|
|
174
|
+
def escape_javascript(javascript)
|
|
175
|
+
if javascript
|
|
176
|
+
javascript.gsub(/(\\|<\/|\r\n|[\n\r"'])/) { JS_ESCAPE_MAP[$1] }
|
|
177
|
+
else
|
|
178
|
+
''
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
module MissionHelper
|
|
2
|
+
helpers do
|
|
3
|
+
|
|
4
|
+
# -------------------------------------------------------------------------
|
|
5
|
+
def load_report
|
|
6
|
+
@old_reports = Wackamole::Mission.find( {}, :sort => [ [:app, Mongo::ASCENDING], [:env, Mongo::ASCENDING] ] ).to_a
|
|
7
|
+
|
|
8
|
+
last_tick = session[:last_tick]
|
|
9
|
+
reset = last_tick.nil?
|
|
10
|
+
last_tick = last_tick || Chronic.parse( '1 minute ago' )
|
|
11
|
+
session[:last_tick] = Time.now
|
|
12
|
+
@reports = Wackamole::Mission.rollups( last_tick.utc, reset )
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# -------------------------------------------------------------------------
|
|
16
|
+
# compute diff delta
|
|
17
|
+
def delta?( diff )
|
|
18
|
+
diff == 0 ? content_tag( :span, diff, :class => "no_diff") : content_tag( :span, "+#{diff}", :class => "diff")
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# -------------------------------------------------------------------------
|
|
22
|
+
# Assign status fg for application
|
|
23
|
+
def assign_class( type, count, diff )
|
|
24
|
+
clazz = case type
|
|
25
|
+
when "faults" : (diff > 0 ? "fault" : "")
|
|
26
|
+
when "perfs" : (diff > 0 ? "perf" : "")
|
|
27
|
+
when "features" : (diff > 0 ? "active" : "inactive")
|
|
28
|
+
else ""
|
|
29
|
+
end
|
|
30
|
+
clazz
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# -------------------------------------------------------------------------
|
|
34
|
+
# Computes count diff since last check point
|
|
35
|
+
def compute_diff( app_name, env, type_name, count )
|
|
36
|
+
old_count = find_report_count( app_name, env, type_name )
|
|
37
|
+
return (count - old_count) if( old_count )
|
|
38
|
+
count
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# =========================================================================
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
# -----------------------------------------------------------------------
|
|
45
|
+
# Find report count for a given report
|
|
46
|
+
def find_report_count( app, env, type )
|
|
47
|
+
@old_reports.each do |report|
|
|
48
|
+
next unless report['app'] == app
|
|
49
|
+
report['envs'].each_pair do |e, details|
|
|
50
|
+
next unless e == env
|
|
51
|
+
details.each_pair do |type_name, count|
|
|
52
|
+
return count if type_name == type
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
nil
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|