rubyrun 0.9.5-x86-linux
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/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
|