rubyrun 0.9.5-x86-mswin32-60
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +13 -0
- data/README +77 -0
- data/bin/Rakefile +11 -0
- data/docs/rubyrun-0.9.5.htm +5937 -0
- data/docs/rubyrun-0.9.5.pdf +0 -0
- data/docs/rubyrun-0.9.5_files/colorschememapping.xml +2 -0
- data/docs/rubyrun-0.9.5_files/filelist.xml +29 -0
- data/docs/rubyrun-0.9.5_files/header.htm +138 -0
- data/docs/rubyrun-0.9.5_files/image001.jpg +0 -0
- data/docs/rubyrun-0.9.5_files/image002.jpg +0 -0
- data/docs/rubyrun-0.9.5_files/image003.jpg +0 -0
- data/docs/rubyrun-0.9.5_files/image004.jpg +0 -0
- data/docs/rubyrun-0.9.5_files/image005.jpg +0 -0
- data/docs/rubyrun-0.9.5_files/image006.jpg +0 -0
- data/docs/rubyrun-0.9.5_files/image007.jpg +0 -0
- data/docs/rubyrun-0.9.5_files/image008.jpg +0 -0
- data/docs/rubyrun-0.9.5_files/image009.jpg +0 -0
- data/docs/rubyrun-0.9.5_files/image010.jpg +0 -0
- data/docs/rubyrun-0.9.5_files/image011.jpg +0 -0
- data/docs/rubyrun-0.9.5_files/image012.jpg +0 -0
- data/docs/rubyrun-0.9.5_files/image013.jpg +0 -0
- data/docs/rubyrun-0.9.5_files/image014.jpg +0 -0
- data/docs/rubyrun-0.9.5_files/image015.jpg +0 -0
- data/docs/rubyrun-0.9.5_files/image016.jpg +0 -0
- data/docs/rubyrun-0.9.5_files/image017.png +0 -0
- data/docs/rubyrun-0.9.5_files/image018.jpg +0 -0
- data/docs/rubyrun-0.9.5_files/image019.jpg +0 -0
- data/docs/rubyrun-0.9.5_files/image020.jpg +0 -0
- data/docs/rubyrun-0.9.5_files/image021.jpg +0 -0
- data/docs/rubyrun-0.9.5_files/image022.png +0 -0
- data/docs/rubyrun-0.9.5_files/themedata.thmx +0 -0
- data/etc/rubyrun_opts.yml +132 -0
- data/ext/extconf.rb +5 -0
- data/ext/rubyrunnative__.c +154 -0
- data/ext/rubyrunnative__.def +2 -0
- data/ext/rubyrunnative__.h +36 -0
- data/ext/rubyrunnative__ppc-darwin.bundle +0 -0
- data/ext/rubyrunnative__x86-darwin.bundle +0 -0
- data/ext/rubyrunnative__x86-linux.so +0 -0
- data/ext/rubyrunnative__x86-mswin32.so +0 -0
- data/lib/rubyrun/rubyrun.rb +2 -0
- data/lib/rubyrun/rubyrun_boot__.rb +79 -0
- data/lib/rubyrun/rubyrun_buffer_mgr__.rb +49 -0
- data/lib/rubyrun/rubyrun_commander__.rb +196 -0
- data/lib/rubyrun/rubyrun_dad__.rb +35 -0
- data/lib/rubyrun/rubyrun_globals.rb +52 -0
- data/lib/rubyrun/rubyrun_html__.rb +136 -0
- data/lib/rubyrun/rubyrun_html_writer__.rb +64 -0
- data/lib/rubyrun/rubyrun_initializer__.rb +313 -0
- data/lib/rubyrun/rubyrun_instrumentor__.rb +226 -0
- data/lib/rubyrun/rubyrun_monitor__.rb +238 -0
- data/lib/rubyrun/rubyrun_report__.rb +109 -0
- data/lib/rubyrun/rubyrun_rss__.rb +97 -0
- data/lib/rubyrun/rubyrun_tracer__.rb +79 -0
- data/lib/rubyrun/rubyrun_utils__.rb +101 -0
- data/lib/rubyrun/rubyrunnative__.so +0 -0
- metadata +115 -0
@@ -0,0 +1,49 @@
|
|
1
|
+
#--------------------------------------------------------------------#
|
2
|
+
# #
|
3
|
+
# (C) Copyright Rubysophic Inc. 2007-2008 #
|
4
|
+
# All rights reserved. #
|
5
|
+
# #
|
6
|
+
# Use, duplication or disclosure of the code is not permitted #
|
7
|
+
# unless licensed. #
|
8
|
+
# #
|
9
|
+
# Last Updated: 7/09/08 #
|
10
|
+
#--------------------------------------------------------------------#
|
11
|
+
# #
|
12
|
+
# RubyRunBufferMgr__ module is responsible for passing the data #
|
13
|
+
# from the inline execution thread to the monitor thread #
|
14
|
+
# #
|
15
|
+
# Two buffers (primary and secondary) are used and the buffers are #
|
16
|
+
# swapped between the inline execution thread and RubyRunMonitor__ #
|
17
|
+
# thread periodically as defined by REPORT_TIMER. The inline #
|
18
|
+
# execution thread pushes data into the primary buffer, when the #
|
19
|
+
# REPORT_TIMER expires, RubyRunMonitor__ thread then takes it over #
|
20
|
+
# and gives the inline execution thread the secondary buffer via #
|
21
|
+
# a quick swap. The same process keeps repeating as the monitor #
|
22
|
+
# timer pops and the primary and secondary keep switched between #
|
23
|
+
# the two threads. #
|
24
|
+
# #
|
25
|
+
#--------------------------------------------------------------------#
|
26
|
+
module RubyRunBufferMgr__
|
27
|
+
|
28
|
+
# Push data into the current buffer
|
29
|
+
# Primary or secondary buffer may be used but it is transparent to the caller
|
30
|
+
def push_current_buffer(metrics)
|
31
|
+
$rubyrun_lock.synchronize {
|
32
|
+
($rubyrun_current_buffer == 1 ? $rubyrun_prime_buffer : $rubyrun_alt_buffer) << metrics
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
# Return the current buffer and swap it with the other one
|
37
|
+
# This method is invoked by the consumer of the data in the buffer
|
38
|
+
def return_and_switch_buffer()
|
39
|
+
$rubyrun_lock.synchronize {
|
40
|
+
if ($rubyrun_current_buffer == 1)
|
41
|
+
$rubyrun_current_buffer == 2
|
42
|
+
$rubyrun_prime_buffer
|
43
|
+
else
|
44
|
+
$rubyrun_current_buffer == 1
|
45
|
+
$rubyrun_alt_buffer
|
46
|
+
end
|
47
|
+
}
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,196 @@
|
|
1
|
+
#-----------------------------------------------------------------#
|
2
|
+
# #
|
3
|
+
# (C) Copyright Rubysophic Inc. 2007-2008 #
|
4
|
+
# All rights reserved. #
|
5
|
+
# #
|
6
|
+
# Use, duplication or disclosure of the code is not permitted #
|
7
|
+
# unless licensed. #
|
8
|
+
# #
|
9
|
+
# Last Updated: 7/18/08 #
|
10
|
+
#-----------------------------------------------------------------#
|
11
|
+
# #
|
12
|
+
# RubyRunCommander__ is a module which handles the commands #
|
13
|
+
# cmd_status, cmd_object_map, cmd_soft_kill and cmd_hard_kill #
|
14
|
+
# #
|
15
|
+
#-----------------------------------------------------------------#
|
16
|
+
module RubyRunCommander__
|
17
|
+
|
18
|
+
# Use Thread.list to list show thread status, and native code to
|
19
|
+
# display the last line # and function of the threads
|
20
|
+
def dump_thread_status
|
21
|
+
(unsupport_function; return) unless $rubyrun_native
|
22
|
+
$rubyrun_thread_status_reporter = RubyRunHTMLWriter.new(@rubyrun_report_folder + '/' + File.basename($0, ".*") + '_' + $$.to_s + '_thread_status.html', nil, shift_age = 10, shift_size = 4096000) unless $rubyrun_thread_status_reporter
|
23
|
+
start_time = Time.now
|
24
|
+
th_data_hash = RubyRunNative__.get_all_top_stacks
|
25
|
+
odd_row ||= true
|
26
|
+
table_content = ''
|
27
|
+
Thread.list.each {|th|
|
28
|
+
thread_id = get_thread_id(th)
|
29
|
+
table_content += sprintf("#{odd_row ? THREAD_STATUS_ODD_ROW : THREAD_STATUS_EVEN_ROW}",
|
30
|
+
thread_id, th.status, get_top_stack(th_data_hash, thread_id))
|
31
|
+
odd_row = !odd_row
|
32
|
+
}
|
33
|
+
html_content = THREAD_STATUS_HTML.sub(/%START_TIMESTAMP%/,start_time.strftime("%H:%M:%S %m/%d/%Y"))
|
34
|
+
html_content.sub!(/%THREAD_STATUS_ROW%/,table_content)
|
35
|
+
$rubyrun_thread_status_reporter.info(html_content)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Dump Controller/Actions response time metrics
|
39
|
+
# metrics structure
|
40
|
+
# metrics[0] Thread ID metrics[1] Timestamp of the request
|
41
|
+
# metrics[2] URL metrics[3] Controller name
|
42
|
+
# metrics[4] Action name metrics[5] Response time
|
43
|
+
# metrics[6] Action time metrics[7] Database IO time
|
44
|
+
# metrics[8] View time metrics[9] Uncaptured time
|
45
|
+
# metrics[10] Dispatch wait time
|
46
|
+
def dump_reports(dump_all_reports = false)
|
47
|
+
buffer = return_and_switch_buffer
|
48
|
+
buffer.each { |metrics|
|
49
|
+
# Last element is 1, representing a request count of 1, used for calculating average response time for this controller/action
|
50
|
+
update_perf_metrics(metrics[3], {metrics[4] => [metrics[5],metrics[6],metrics[7],metrics[8],metrics[9],metrics[10],1]})
|
51
|
+
}
|
52
|
+
@rubyrun_req_count ||= 0
|
53
|
+
@rubyrun_req_count += buffer.length
|
54
|
+
if $rubyrun_config['OUTPUT'].include?(RUBYRUN_OUTPUT_PERF_SUMMARY) && dump_all_reports
|
55
|
+
create_rss_channels if (!$rubyrun_perf_summary_rss && $rubyrun_rails_env)
|
56
|
+
add_perf_summary_rss_item(@rubyrun_req_count)
|
57
|
+
@rubyrun_req_count = 0
|
58
|
+
end
|
59
|
+
if $rubyrun_config['OUTPUT'].include?(RUBYRUN_OUTPUT_TXN_LOG)
|
60
|
+
create_csv_files unless $rubyrun_txn_log_reporter
|
61
|
+
add_txn_log_csv_item(buffer)
|
62
|
+
end
|
63
|
+
buffer.clear # Clear the buffer so that the main thread will push the data into a blank bucket
|
64
|
+
end
|
65
|
+
|
66
|
+
# The way to do soft/hard kill is to performa a thr.raise on the thread
|
67
|
+
# from the thread monitor. Using the begin/rescue created around the block
|
68
|
+
# in Thread.new by RubyRunInstrumentor__, the raise will be rescued
|
69
|
+
# and $@ is then extracted to a global hash.
|
70
|
+
# Softkill only kills non-main threads. Hardkill kills the main thread also
|
71
|
+
# but as the last step.
|
72
|
+
def kill_threads(monitor_thr)
|
73
|
+
(unsupport_function; return) unless $rubyrun_native
|
74
|
+
if !$rubyrun_thread_dump_reporter
|
75
|
+
$rubyrun_thread_dump_reporter = Logger.new(@rubyrun_report_folder + '/' + File.basename($0, ".*") + '_' + $$.to_s + '_thread_dump.txt', shift_age = 10, shift_size = 4096000)
|
76
|
+
$rubyrun_thread_dump_reporter.level = Logger::INFO
|
77
|
+
class << $rubyrun_thread_dump_reporter
|
78
|
+
include RubyRunUtils__
|
79
|
+
def format_message (severity, timestamp, progname, msg)
|
80
|
+
"[#{timestamp.strftime("%Y-%m-%d %H:%M:%S")}.#{("%.3f" % timestamp.to_f).split('.')[1]}] #{get_thread_id} #{msg}\n"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
th_data_hash = RubyRunNative__.get_all_top_stacks
|
85
|
+
j_th_id = return_joined_thread(th_data_hash)
|
86
|
+
Thread.list.each {|th|
|
87
|
+
th_id = get_thread_id(th)
|
88
|
+
if th.status == 'sleep' && th_id != get_thread_id && th_id != get_thread_id(monitor_thr) &&
|
89
|
+
th_id != get_thread_id(Thread.main) && th_id != j_th_id
|
90
|
+
$rubyrun_thread_dump_reporter.info "*** Raising exception #{RUBYRUN_KILL_3_STRING} to #{get_thread_id(th)} ***"
|
91
|
+
th.raise ThreadError, RUBYRUN_KILL_3_STRING
|
92
|
+
end
|
93
|
+
}
|
94
|
+
sleep 3
|
95
|
+
back_trace_all(th_data_hash)
|
96
|
+
hard_kill = hard_kill?
|
97
|
+
remove_cmd_folder
|
98
|
+
Thread.main.raise ThreadError, RUBYRUN_KILL_3_STRING if hard_kill
|
99
|
+
end
|
100
|
+
|
101
|
+
# Show the top 20 Ruby classes which have the largest no. of instances in memory
|
102
|
+
# The snapshot is taken after a gc call is made
|
103
|
+
def dump_object_map
|
104
|
+
start_time = Time.now
|
105
|
+
$rubyrun_obj_map_reporter = RubyRunHTMLWriter.new(@rubyrun_report_folder + '/' + File.basename($0, ".*") + '_' + $$.to_s + '_object_map.html', nil, shift_age = 10, shift_size = 4096000) unless $rubyrun_obj_map_reporter
|
106
|
+
object_map = Hash.new
|
107
|
+
ttl_object = 0
|
108
|
+
ObjectSpace.garbage_collect
|
109
|
+
ObjectSpace.each_object { |obj|
|
110
|
+
ttl_object += 1
|
111
|
+
object_map.has_key?(obj.class) ? object_map[obj.class] += 1 : object_map[obj.class] = 1
|
112
|
+
}
|
113
|
+
results = object_map.sort{|a,b| a[1]<=>b[1]}.reverse!
|
114
|
+
table_content = ''
|
115
|
+
odd_row ||=true
|
116
|
+
20.times {|i|
|
117
|
+
table_content += sprintf("#{odd_row ? OBJ_MAP_ODD_ROW : OBJ_MAP_EVEN_ROW}",
|
118
|
+
results[i][0], results[i][1].to_s)
|
119
|
+
odd_row = !odd_row
|
120
|
+
}
|
121
|
+
html_content = OBJ_MAP_HTML.sub(/%START_TIMESTAMP%/,start_time.strftime("%H:%M:%S %m/%d/%Y"))
|
122
|
+
html_content.sub!(/%OBJ_MAP_ROW%/,table_content)
|
123
|
+
$rubyrun_obj_map_reporter.info(html_content)
|
124
|
+
end
|
125
|
+
|
126
|
+
# metrics hash is a global collection point for all metrics (averaged)
|
127
|
+
# for all actions by controller
|
128
|
+
# Use serialization before updating this global hash
|
129
|
+
# Structure of $rubyrun_metrics_hash:
|
130
|
+
# controller_name => {action_name => [response_time, action_time,
|
131
|
+
# db_io_time, view_time,
|
132
|
+
# uncaptured_time, dispatch_wait_time,
|
133
|
+
# request_count]}
|
134
|
+
def update_perf_metrics(controller, action_metrics_hash)
|
135
|
+
$rubyrun_metrics_hash[controller].merge!(action_metrics_hash) {|action, o_metrics, new_metrics|
|
136
|
+
o_metrics.each_index { |x|
|
137
|
+
(o_metrics[x] += new_metrics[x]; break) if x == (o_metrics.length-1) # Calculate the total request count for this controller/action
|
138
|
+
o_metrics[x] = (o_metrics[x] * o_metrics.last + new_metrics[x])/(o_metrics.last + new_metrics.last).to_f
|
139
|
+
}
|
140
|
+
o_metrics
|
141
|
+
}
|
142
|
+
end
|
143
|
+
|
144
|
+
# If a thread is joined this method returns the joining thread ID
|
145
|
+
def return_joined_thread(th_data_hash)
|
146
|
+
th_data_hash.each {|th, top_stack|
|
147
|
+
if th.to_s.include?(get_thread_id(Thread.main))
|
148
|
+
top_stack[0] =~ /\*\*(.+?)\*\*/
|
149
|
+
return $1
|
150
|
+
end
|
151
|
+
}
|
152
|
+
end
|
153
|
+
|
154
|
+
# Remove the cmd_kill-3 folder or file if any
|
155
|
+
def remove_cmd_folder
|
156
|
+
[RUBYRUN_CMD_SOFT_KILL, RUBYRUN_CMD_HARD_KILL].each { |cmd|
|
157
|
+
path = $rubyrun_working_dir + cmd + '_' + Process.pid.to_s
|
158
|
+
next unless File.exist?(path)
|
159
|
+
File.directory?(path) ? Dir.delete(path) : File.delete(path)
|
160
|
+
}
|
161
|
+
end
|
162
|
+
|
163
|
+
# If exists, indicate to the monitor thread that a thread
|
164
|
+
# status report is requested
|
165
|
+
def thread_status?
|
166
|
+
File.exists?($rubyrun_working_dir + RUBYRUN_CMD_STATUS)
|
167
|
+
end
|
168
|
+
|
169
|
+
# If exists, indicate to the monitor thread that a soft kill
|
170
|
+
# (kill all threads except the main thread) command is sent
|
171
|
+
def soft_kill?
|
172
|
+
File.exists?($rubyrun_working_dir + RUBYRUN_CMD_SOFT_KILL + '_' + Process.pid.to_s)
|
173
|
+
end
|
174
|
+
|
175
|
+
# If exists, indicate to the monitor thread that a hard kill
|
176
|
+
# (kill all threads including the main thread) command is sent
|
177
|
+
def hard_kill?
|
178
|
+
File.exists?($rubyrun_working_dir + RUBYRUN_CMD_HARD_KILL + '_' + Process.pid.to_s)
|
179
|
+
end
|
180
|
+
|
181
|
+
# If exists, indicate to the montior thread that a object map is requested
|
182
|
+
def object_map?
|
183
|
+
File.exists?($rubyrun_working_dir + RUBYRUN_CMD_OBJECT_MAP)
|
184
|
+
end
|
185
|
+
|
186
|
+
# If exists, indicate to the monitor thread to exit
|
187
|
+
def exit_monitor?
|
188
|
+
File.exists?($rubyrun_working_dir + RUBYRUN_CMD_EXIT)
|
189
|
+
end
|
190
|
+
|
191
|
+
# Log if native library can't be loaded or not found
|
192
|
+
def unsupport_function
|
193
|
+
$rubyrun_logger.info "Native library not available. Function not supported."
|
194
|
+
end
|
195
|
+
|
196
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
#---------------------------------------------------------------#
|
2
|
+
# #
|
3
|
+
# (C) Copyright Rubysophic Inc. 2007-2008 #
|
4
|
+
# All rights reserved. #
|
5
|
+
# #
|
6
|
+
# Use, duplication or disclosure of the code is not permitted #
|
7
|
+
# unless licensed. #
|
8
|
+
# Dynamic Application Discovery #
|
9
|
+
# #
|
10
|
+
# Last Updated: 7/09/08 #
|
11
|
+
#---------------------------------------------------------------#
|
12
|
+
# #
|
13
|
+
# Dynamic Application Discovery lists out the name of a method #
|
14
|
+
# as it is being added to the ruby process. #
|
15
|
+
# #
|
16
|
+
#---------------------------------------------------------------#
|
17
|
+
module RubyRunDad__
|
18
|
+
|
19
|
+
# perform dynamic application discovery if requested by printing
|
20
|
+
# out the class and method name of the method being added
|
21
|
+
def get_dad(type, klass, id)
|
22
|
+
print_method_added(type, klass, id) if $rubyrun_dad
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
# print the dynamic method added message
|
28
|
+
def print_method_added(type, obj, id)
|
29
|
+
if type == 'i'
|
30
|
+
$rubyrun_logger.info "#{obj.to_s}.#{id.id2name} added as an instance method"
|
31
|
+
else
|
32
|
+
$rubyrun_logger.info "#{obj.to_s}.#{id.id2name} added as an singleton method"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
#---------------------------------------------------------------#
|
2
|
+
# #
|
3
|
+
# (C) Copyright Rubysophic Inc. 2007-2008 #
|
4
|
+
# All rights reserved. #
|
5
|
+
# #
|
6
|
+
# Use, duplication or disclosure of the code is not permitted #
|
7
|
+
# unless licensed. #
|
8
|
+
# #
|
9
|
+
# Last Updated: 7/09/08 #
|
10
|
+
#---------------------------------------------------------------#
|
11
|
+
# #
|
12
|
+
# Provide CONSTANTS for RubyRun modules #
|
13
|
+
# #
|
14
|
+
#---------------------------------------------------------------#
|
15
|
+
module RubyRunGlobals
|
16
|
+
|
17
|
+
RUBYRUN_PREFIX = 'rubyrunX'
|
18
|
+
RUBYRUN_PREFIX_LENGTH = RUBYRUN_PREFIX.length
|
19
|
+
RUBYRUN_HIGHLIGHT_THRESHOLD = 1
|
20
|
+
RUBYRUN_FIREWALL_HASH = {"Gem" => [], "gem" => [], "FileUtils::Verbose" => [], "FileUtils" => [],
|
21
|
+
"Module" => [], "Object" => [], "Time" => [], "Logger" => [], "Thread" => [],
|
22
|
+
"*" => ['method_added', 'initialize', 'singleton_method_added', 'send', 'caller']}
|
23
|
+
RUBYRUN_WORKING_DIR_NAME = 'rubyrun'
|
24
|
+
RUBYRUN_ETC_DIR = 'etc'
|
25
|
+
RUBYRUN_LOG = '/log'
|
26
|
+
RUBYRUN_REPORT = '/report'
|
27
|
+
RUBYRUN_SIGNATURE = '/signatures'
|
28
|
+
RUBYRUN_INCLUDE_HASH_FILE = '/include_hash_file'
|
29
|
+
RUBYRUN_EXCLUDE_HASH_FILE = '/exclude_hash_file'
|
30
|
+
RUBYRUN_DIR_HASH_FILE = '/dir_hash_file'
|
31
|
+
RUBYRUN_CMD_SOFT_KILL = '/cmd_soft_kill'
|
32
|
+
RUBYRUN_CMD_HARD_KILL = '/cmd_hard_kill'
|
33
|
+
RUBYRUN_CMD_STATUS = '/cmd_status'
|
34
|
+
RUBYRUN_CMD_EXIT = '/cmd_exit'
|
35
|
+
RUBYRUN_CMD_OBJECT_MAP = '/cmd_object_map'
|
36
|
+
RUBYRUN_MONITOR_TIMER = 10
|
37
|
+
RUBYRUN_OUTPUT_PERF_SUMMARY = 'perf_summary'
|
38
|
+
RUBYRUN_OUTPUT_TXN_LOG = 'txn_log'
|
39
|
+
RUBYRUN_KILL_3_STRING = 'RUBYRUN kill -3'
|
40
|
+
RUBYRUN_OPTS_FILE = '/rubyrun_opts.yml'
|
41
|
+
RUBYRUN_PROP_DEFAULTS = {"APP_PATHS"=>[], "EXCLUDE_HASH"=>{}, "INCLUDE_HASH"=>{},
|
42
|
+
"DEBUG_ARGS"=>false, "DEBUG_OBJ"=>false, "DAD"=>false,
|
43
|
+
"REPORT_TIMER"=>60, "REPORT_SHIFT_AGE"=>60,
|
44
|
+
"OUTPUT" => ["#{RUBYRUN_OUTPUT_PERF_SUMMARY}","#{RUBYRUN_OUTPUT_TXN_LOG}","#{RUBYRUN_OUTPUT_PERF_SUMMARY}"],
|
45
|
+
"RSS_PATH" => nil, "TRACE_HASH"=>{}, "DB_ADAPTER_HASH"=>{}}
|
46
|
+
RUBYRUN_ACTIVERECORD = 'ActiveRecord::Base'
|
47
|
+
RUBYRUN_VIEW_HASH = {'ActionView::Base' => ['pick_template_extension','render_file']}
|
48
|
+
RUBYRUN_THREAD_END_HASH = {'WEBrick::HTTPServer' => ['run'], 'Mongrel::HttpServer' => ['process_client']}
|
49
|
+
RUBYRUN_OUTER_DISPATCH_HASH = {'Mongrel::Rails::RailsHandler' => ['process'], 'DispatchServlet' => ['service']}
|
50
|
+
RUBYRUN_INNER_DISPATCH_HASH = { 'Dispatcher' => ['dispatch'], 'ActionController::Dispatcher' => ['dispatch']}
|
51
|
+
|
52
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
#-----------------------------------------------------------------#
|
2
|
+
# #
|
3
|
+
# (C) Copyright Rubysophic Inc. 2007-2008 #
|
4
|
+
# All rights reserved. #
|
5
|
+
# #
|
6
|
+
# Use, duplication or disclosure of the code is not permitted #
|
7
|
+
# unless licensed. #
|
8
|
+
# #
|
9
|
+
# Last Updated: 7/08/08 #
|
10
|
+
#-----------------------------------------------------------------#
|
11
|
+
# #
|
12
|
+
# RubyRunHTML__ defines HTML templates and assigns them to #
|
13
|
+
# various constants to be used by other reporter modules. #
|
14
|
+
# The templates include thread status, method trace and RSS #
|
15
|
+
# content. #
|
16
|
+
# #
|
17
|
+
#-----------------------------------------------------------------#
|
18
|
+
module RubyRunHTML__
|
19
|
+
OBJ_MAP_HTML = "<table cellspacing='2' width='55%'>
|
20
|
+
<tr align='middle' bgcolor='#43bfc7'>
|
21
|
+
<th colspan='2'><font face='Helvetica' size='2' color='white'>Top 20 Ruby classes with the largest number of objects (%START_TIMESTAMP%)</font></th></tr>
|
22
|
+
<tr align='middle' bgcolor='#43bfc7'>
|
23
|
+
<th><font face='Helvetica' size='2' color='white'>Class name</font></th>
|
24
|
+
<th><font face='Helvetica' size='2' color='white'>Number of objects</font></th>
|
25
|
+
%OBJ_MAP_ROW%
|
26
|
+
</table><br></br>"
|
27
|
+
OBJ_MAP_ODD_ROW = "<tr align='middle'>
|
28
|
+
<td align='left' bgcolor='#afdcec'><font face='Tahoma' size='2' color='black'>%s</font></td>
|
29
|
+
<td align='left' bgcolor='#afdcec'><font face='Tahoma' size='2' color='black'>%s</font></td>"
|
30
|
+
OBJ_MAP_EVEN_ROW = "<tr align='middle'>
|
31
|
+
<td align='left'><font face='Tahoma' size='2' color='black'>%s</font></td>
|
32
|
+
<td align='left'><font face='Tahoma' size='2' color='black'>%s</font></td>"
|
33
|
+
THREAD_STATUS_HTML = "<table cellspacing='2' width='100%'>
|
34
|
+
<tr align='middle' bgcolor='#43bfc7'>
|
35
|
+
<th colspan='3'><font face='Helvetica' size='2' color='white'>RubyRun Thread Status Starts (%START_TIMESTAMP%)</font></th>
|
36
|
+
<tr align='middle' bgcolor='#43bfc7'>
|
37
|
+
<th><font face='Helvetica' size='2' color='white'>Thread ID</font></th>
|
38
|
+
<th><font face='Helvetica' size='2' color='white'>Status</font></th>
|
39
|
+
<th><font face='Helvetica' size='2' color='white'>Top of the stack</font></th>
|
40
|
+
%THREAD_STATUS_ROW%
|
41
|
+
</table><br></br>"
|
42
|
+
THREAD_STATUS_ODD_ROW = "<tr align='middle'>
|
43
|
+
<td bgcolor='#afdcec'><font face='Tahoma' size='2' color='black'>%s</font></td>
|
44
|
+
<td bgcolor='#afdcec'><font face='Tahoma' size='2' color='black'>%s</font></td>
|
45
|
+
<td align='left' bgcolor='#afdcec'><font face='Tahoma' size='2' color='black'>%s</font></td>"
|
46
|
+
THREAD_STATUS_EVEN_ROW = "<tr align='middle'>
|
47
|
+
<td><font face='Tahoma' size='2' color='black'>%s</font></td>
|
48
|
+
<td><font face='Tahoma' size='2' color='black'>%s</font></td>
|
49
|
+
<td align='left'><font face='Tahoma' size='2' color='black'>%s</font></td></tr>"
|
50
|
+
|
51
|
+
METHOD_TRACE_HEADER = "<table cellspacing=2 width=100%>
|
52
|
+
<tr align=center bgcolor=#43BFC7>
|
53
|
+
<th><font face=Helvetica size=2 color=white>Time</font></th>
|
54
|
+
<th><font face=Helvetica size=2 color=white>Thread ID</font></th>
|
55
|
+
<th><font face=Helvetica size=2 color=white>Method Entry/Exit</font></th>
|
56
|
+
<th><font face=Helvetica size=2 color=white>Time Taken</font></th>
|
57
|
+
<th><font face=Helvetica size=2 color=white>Class</font></th>
|
58
|
+
<th><font face=Helvetica size=2 color=white>Method</font></th>
|
59
|
+
<th><font face=Helvetica size=2 color=white>Parameter Value(s)</font></th>
|
60
|
+
<th><font face=Helvetica size=2 color=white>Caller Object Class</font></th>
|
61
|
+
<th><font face=Helvetica size=2 color=white>Caller Method</font></th></tr>"
|
62
|
+
METHOD_TRACE_ODD_ROW = "<tr align=center>
|
63
|
+
<td bgcolor=#AFDCEC><font face='Tahoma' size=2 color=black>%s</font></td>
|
64
|
+
<td bgcolor=#AFDCEC><font face='Tahoma' size=2 color=black>%s</font></td>
|
65
|
+
<td bgcolor=#AFDCEC><font face='Tahoma' size=2 color=black>%s</font></td>
|
66
|
+
<td bgcolor=%s><font face='Tahoma' size=2 color=black>%s</font></td>
|
67
|
+
<td align=left bgcolor=#AFDCEC><font face='Tahoma' size=2 color=black>%s</font></td>
|
68
|
+
<td align=left bgcolor=#AFDCEC><font face='Tahoma' size=2 color=black>%s</font></td>
|
69
|
+
<td align=left bgcolor=#AFDCEC><font face='Tahoma' size=2 color=black>%s</font></td>
|
70
|
+
<td align=left bgcolor=#AFDCEC><font face='Tahoma' size=2 color=black>%s</font></td>
|
71
|
+
<td align=left bgcolor=#AFDCEC><font face='Tahoma' size=2 color=black>%s</font></td></tr>"
|
72
|
+
METHOD_TRACE_EVEN_ROW = "<tr align=center>
|
73
|
+
<td><font face='Tahoma' size=2 color=black>%s</font></td>
|
74
|
+
<td><font face='Tahoma' size=2 color=black>%s</font></td>
|
75
|
+
<td><font face='Tahoma' size=2 color=black>%s</font></td>
|
76
|
+
<td bgcolor=%s><font face='Tahoma' size=2 color=black>%s</font></td>
|
77
|
+
<td align=left><font face='Tahoma' size=2 color=black>%s</font></td>
|
78
|
+
<td align=left><font face='Tahoma' size=2 color=black>%s</font></td>
|
79
|
+
<td align=left><font face='Tahoma' size=2 color=black>%s</font></td>
|
80
|
+
<td align=left><font face='Tahoma' size=2 color=black>%s</font></td>
|
81
|
+
<td align=left><font face='Tahoma' size=2 color=black>%s</font></td></tr>"
|
82
|
+
|
83
|
+
THROUGHPUT_HTML = "<p align=center><font size='3' face='Verdana'>Performance summary of %APPS_NAME% as of %TIMESTAMP%</font></p>
|
84
|
+
<table id=tblgraph align=center width=80 cellpadding=2 cellspacing=0 border=0>
|
85
|
+
<tr><td bgcolor=WHITE align=center valign=middle width=22 style='writing-mode:tb-rl'><font face=arial size='-1'>Average throughput per min</font></td>%THROUGHPUT_BAR_TABLE%</tr>
|
86
|
+
<tr bgcolor=#505050>
|
87
|
+
<td align=center bordor=1 bgcolor=#FFFFFF> </td>%THROUGHPUT_LABEL_TABLE%
|
88
|
+
<td bgcolor=white align=center><font face=arial size='-2' color=black>Time</font></td>
|
89
|
+
</tr></table>"
|
90
|
+
THROUGHPUT_BAR_TABLE = "<td align=center valign=bottom width=22>
|
91
|
+
<font face=arial size='-2'>%s</font><br>
|
92
|
+
<div style='writing-mode:tb-rl; background-color:firebrick; width:30; height:%d;' />
|
93
|
+
</td>"
|
94
|
+
THROUGHPUT_LABEL_TABLE = "<td align=center><font face=arial size='-2' color=white>%s</font></td>"
|
95
|
+
TOP_SLOWEST_REQUESTS_HTML ="<p><font size='2' face='Verdana'>Top 10 Slowest Requests</font></p>
|
96
|
+
<table cellspacing=0 width=50%%><tr bgcolor=FF6633>
|
97
|
+
<th><font face=Helvetica size=2 color=#FFFFFF>Controller/Action<font></th>
|
98
|
+
<th><font face=Helvetica size=2 color=#FFFFFF>Response Time<font></th></tr>
|
99
|
+
%TOP_SLOWEST_REQUESTS_TABLE%
|
100
|
+
</table>"
|
101
|
+
TOP_SLOWEST_REQUESTS_TABLE="<tr><td align=left bgcolor=585858><font face=Helvetica size=2 color=white>%s</font></td>
|
102
|
+
<td><table><tr><td bgcolor=firebrick><div style='writing-mode:tb-rl; background-color:firebrick; width:%d; height:5;' /></td><td><font face=Helvetica SIZE=1>%0.3fs</font></td></tr></table></td></tr>"
|
103
|
+
REQ_PERF_BREAKDOWN_HTML ="<p><font size='2' face='Verdana'>Request Performance Breakdown</font></p>
|
104
|
+
<table cellspacing=0 width=100%>
|
105
|
+
<tr bgcolor=FF6633>
|
106
|
+
<th><font face=Helvetica size=2 color=#FFFFFF>Controller/Action</font></th>
|
107
|
+
<th><font face=Helvetica size=2 color=#FFFFFF>Request Count</font></th>
|
108
|
+
<th><font face=Helvetica size=2 color=#FFFFFF>Response Time</font></th>
|
109
|
+
<th><font face=Helvetica size=2 color=#FFFFFF>Action Time</font></th>
|
110
|
+
<th><font face=Helvetica size=2 color=#FFFFFF>Database IO Time</font></th>
|
111
|
+
<th><font face=Helvetica size=2 color=#FFFFFF>View Time</font></th>
|
112
|
+
<th><font face=Helvetica size=2 color=#FFFFFF>Dispatch Delay Time</font></th>
|
113
|
+
<th><font face=Helvetica size=2 color=#FFFFFF>Uncaptured Time</font></th>
|
114
|
+
</tr>%REQ_PERF_BREAKDOWN_TABLE%</table>
|
115
|
+
<font size='1' face='Verdana'>Note: Process components are results of functional decomposition which overlap each other. As a result, times do not add up to 100%. The hotspots of performance slowdowns, however, are easily accountable from functional standpoint.</font><br></br>"
|
116
|
+
REQ_PERF_BREAKDOWN_TABLE_ODD='<tr align=center>
|
117
|
+
<td align=left bgcolor=585858><font face=Helvetica size=2 color=white>%s</font></td>
|
118
|
+
<td bgcolor=C0C0C0><font face=Helvetica size=2 color=black>%d</font></td>
|
119
|
+
<td bgcolor=C0C0C0><font face=Helvetica size=2 color=black>%0.3fs</font></td>
|
120
|
+
<td bgcolor=C0C0C0><font face=Helvetica size=2 color=black>%0.3fs (%d%%)</font></td>
|
121
|
+
<td bgcolor=C0C0C0><font face=Helvetica size=2 color=black>%0.3fs (%d%%)</font></td>
|
122
|
+
<td bgcolor=C0C0C0><font face=Helvetica size=2 color=black>%0.3fs (%d%%)</font></td>
|
123
|
+
<td bgcolor=C0C0C0><font face=Helvetica size=2 color=black>%0.3fs (%d%%)</font></td>
|
124
|
+
<td bgcolor=C0C0C0><font face=Helvetica size=2 color=black>%0.3fs</font></td>
|
125
|
+
</tr>'
|
126
|
+
REQ_PERF_BREAKDOWN_TABLE_EVEN='<tr align=center>
|
127
|
+
<td align=left bgcolor=585858><font face=Helvetica size=2 color=white>%s</font></td>
|
128
|
+
<td><font face=Helvetica size=2 color=black>%d</font></td>
|
129
|
+
<td><font face=Helvetica size=2 color=black>%0.3fs </font></td>
|
130
|
+
<td><font face=Helvetica size=2 color=black>%0.3fs (%d%%)</font></td>
|
131
|
+
<td><font face=Helvetica size=2 color=black>%0.3fs (%d%%)</font></td>
|
132
|
+
<td><font face=Helvetica size=2 color=black>%0.3fs (%d%%)</font></td>
|
133
|
+
<td><font face=Helvetica size=2 color=black>%0.3fs (%d%%)</font></td>
|
134
|
+
<td><font face=Helvetica size=2 color=black>%0.3fs</font></td>
|
135
|
+
</tr>'
|
136
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
#----------------------------------------------------------------#
|
2
|
+
# #
|
3
|
+
# (C) Copyright Rubysophic Inc. 2007-2008 #
|
4
|
+
# All rights reserved. #
|
5
|
+
# #
|
6
|
+
# Use, duplication or disclosure of the code is not permitted #
|
7
|
+
# unless licensed. #
|
8
|
+
# #
|
9
|
+
# Last Updated: 7/8/08 #
|
10
|
+
#----------------------------------------------------------------#
|
11
|
+
# #
|
12
|
+
# RubyRunHTMLWriter extends Ruby Logger. It makes use of the #
|
13
|
+
# rotating mechanism in Logger and it is used for writing the #
|
14
|
+
# reports in HTML format. The add_log_header method is overidden #
|
15
|
+
# because by default, Ruby Logger writes a header at the #
|
16
|
+
# beginning of each file it creates and such a header is not #
|
17
|
+
# required in the RubyRun reports. #
|
18
|
+
# #
|
19
|
+
#----------------------------------------------------------------#
|
20
|
+
require 'logger'
|
21
|
+
|
22
|
+
class RubyRunHTMLWriter < Logger
|
23
|
+
|
24
|
+
def initialize(logdev, header, shift_age = 0, shift_size = 1048576)
|
25
|
+
@progname = nil
|
26
|
+
@level = DEBUG
|
27
|
+
@default_formatter = Formatter.new
|
28
|
+
@formatter = nil
|
29
|
+
@logdev = nil
|
30
|
+
if logdev
|
31
|
+
@logdev = RubyRunHTMLDevice.new(logdev, header, :shift_age => shift_age,
|
32
|
+
:shift_size => shift_size)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def format_message (severity, timestamp, progname, msg)
|
37
|
+
msg
|
38
|
+
end
|
39
|
+
|
40
|
+
class RubyRunHTMLDevice < Logger::LogDevice
|
41
|
+
|
42
|
+
def initialize(log = nil, header = nil, opt = {})
|
43
|
+
@header = header
|
44
|
+
@dev = @filename = @shift_age = @shift_size = nil
|
45
|
+
@mutex = LogDeviceMutex.new
|
46
|
+
if log.respond_to?(:write) and log.respond_to?(:close)
|
47
|
+
@dev = log
|
48
|
+
else
|
49
|
+
@dev = open_logfile(log)
|
50
|
+
@dev.sync = true
|
51
|
+
@filename = log
|
52
|
+
@shift_age = opt[:shift_age] || 7
|
53
|
+
@shift_size = opt[:shift_size] || 1048576
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def add_log_header(file)
|
60
|
+
file.write(@header) if @header
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|