RubyRun_CE 0.9.0-powerpc-darwin
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +13 -0
- data/README +75 -0
- data/Rakefile +241 -0
- data/bin/confgure +2 -0
- data/docs/RubyRunCE_09.htm +6346 -0
- data/docs/RubyRunCE_09.pdf +0 -0
- data/docs/RubyRunCE_09_files/colorschememapping.xml +2 -0
- data/docs/RubyRunCE_09_files/filelist.xml +29 -0
- data/docs/RubyRunCE_09_files/header.htm +142 -0
- data/docs/RubyRunCE_09_files/image001.jpg +0 -0
- data/docs/RubyRunCE_09_files/image002.jpg +0 -0
- data/docs/RubyRunCE_09_files/image003.jpg +0 -0
- data/docs/RubyRunCE_09_files/image004.jpg +0 -0
- data/docs/RubyRunCE_09_files/image005.jpg +0 -0
- data/docs/RubyRunCE_09_files/image006.jpg +0 -0
- data/docs/RubyRunCE_09_files/image007.jpg +0 -0
- data/docs/RubyRunCE_09_files/image008.jpg +0 -0
- data/docs/RubyRunCE_09_files/image009.jpg +0 -0
- data/docs/RubyRunCE_09_files/image010.jpg +0 -0
- data/docs/RubyRunCE_09_files/image011.jpg +0 -0
- data/docs/RubyRunCE_09_files/image012.jpg +0 -0
- data/docs/RubyRunCE_09_files/image013.jpg +0 -0
- data/docs/RubyRunCE_09_files/image014.jpg +0 -0
- data/docs/RubyRunCE_09_files/image015.jpg +0 -0
- data/docs/RubyRunCE_09_files/image016.jpg +0 -0
- data/docs/RubyRunCE_09_files/image017.png +0 -0
- data/docs/RubyRunCE_09_files/image018.jpg +0 -0
- data/docs/RubyRunCE_09_files/image019.jpg +0 -0
- data/docs/RubyRunCE_09_files/image020.jpg +0 -0
- data/docs/RubyRunCE_09_files/image021.jpg +0 -0
- data/docs/RubyRunCE_09_files/image022.png +0 -0
- data/docs/RubyRunCE_09_files/themedata.thmx +0 -0
- data/etc/rubyrun_opts.yml +132 -0
- data/ext/extconf.rb +4 -0
- data/ext/rubyrunnative__.bundle +0 -0
- data/ext/rubyrunnative__.c +154 -0
- data/ext/rubyrunnative__.def +2 -0
- data/ext/rubyrunnative__.h +36 -0
- data/ext/rubyrunnative__.so +0 -0
- data/ext/rubyrunnative__linux.so +0 -0
- data/html/classes/Module.html +174 -0
- data/html/classes/Object.html +151 -0
- data/html/classes/RubyRunBufferMgr__.html +182 -0
- data/html/classes/RubyRunCommander__.html +578 -0
- data/html/classes/RubyRunDad__.html +144 -0
- data/html/classes/RubyRunGlobals.html +248 -0
- data/html/classes/RubyRunHTMLWriter.html +186 -0
- data/html/classes/RubyRunHTMLWriter/RubyRunHTMLDevice.html +157 -0
- data/html/classes/RubyRunHTML__.html +198 -0
- data/html/classes/RubyRunInitializer__.html +821 -0
- data/html/classes/RubyRunInstrumentor__.html +576 -0
- data/html/classes/RubyRunMonitor__.html +298 -0
- data/html/classes/RubyRunRSS.html +302 -0
- data/html/classes/RubyRunReport__.html +294 -0
- data/html/classes/RubyRunTracer__.html +253 -0
- data/html/classes/RubyRunUtils__.html +376 -0
- data/html/created.rid +1 -0
- data/html/files/LICENSE.html +119 -0
- data/html/files/README.html +196 -0
- data/html/files/lib/rubyrun/rubyrun_buffer_mgr___rb.html +101 -0
- data/html/files/lib/rubyrun/rubyrun_commander___rb.html +101 -0
- data/html/files/lib/rubyrun/rubyrun_dad___rb.html +101 -0
- data/html/files/lib/rubyrun/rubyrun_globals_rb.html +101 -0
- data/html/files/lib/rubyrun/rubyrun_html___rb.html +101 -0
- data/html/files/lib/rubyrun/rubyrun_html_writer___rb.html +108 -0
- data/html/files/lib/rubyrun/rubyrun_initializer___rb.html +112 -0
- data/html/files/lib/rubyrun/rubyrun_instrumentor___rb.html +116 -0
- data/html/files/lib/rubyrun/rubyrun_monitor___rb.html +116 -0
- data/html/files/lib/rubyrun/rubyrun_rb.html +121 -0
- data/html/files/lib/rubyrun/rubyrun_report___rb.html +101 -0
- data/html/files/lib/rubyrun/rubyrun_rss___rb.html +108 -0
- data/html/files/lib/rubyrun/rubyrun_tracer___rb.html +110 -0
- data/html/files/lib/rubyrun/rubyrun_utils___rb.html +108 -0
- data/html/files/lib/rubyrunm_rb.html +116 -0
- data/html/fr_class_index.html +42 -0
- data/html/fr_file_index.html +43 -0
- data/html/fr_method_index.html +96 -0
- data/html/index.html +24 -0
- data/html/rdoc-style.css +208 -0
- data/lib/rubyrun/rubyrun.rb +78 -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 +51 -0
- data/lib/rubyrun/rubyrun_html__.rb +136 -0
- data/lib/rubyrun/rubyrun_html_writer__.rb +64 -0
- data/lib/rubyrun/rubyrun_initializer__.rb +286 -0
- data/lib/rubyrun/rubyrun_instrumentor__.rb +226 -0
- data/lib/rubyrun/rubyrun_monitor__.rb +237 -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 +98 -0
- data/lib/rubyrun/rubyrunnative__.bundle +0 -0
- data/lib/rubyrunm.rb +10 -0
- metadata +149 -0
@@ -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,51 @@
|
|
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 = 'RUBYRUN_WORKING_DIR'
|
24
|
+
RUBYRUN_LOG = '/log'
|
25
|
+
RUBYRUN_REPORT = '/report'
|
26
|
+
RUBYRUN_SIGNATURE = '/signatures'
|
27
|
+
RUBYRUN_INCLUDE_HASH_FILE = '/include_hash_file'
|
28
|
+
RUBYRUN_EXCLUDE_HASH_FILE = '/exclude_hash_file'
|
29
|
+
RUBYRUN_DIR_HASH_FILE = '/dir_hash_file'
|
30
|
+
RUBYRUN_CMD_SOFT_KILL = '/cmd_soft_kill'
|
31
|
+
RUBYRUN_CMD_HARD_KILL = '/cmd_hard_kill'
|
32
|
+
RUBYRUN_CMD_STATUS = '/cmd_status'
|
33
|
+
RUBYRUN_CMD_EXIT = '/cmd_exit'
|
34
|
+
RUBYRUN_CMD_OBJECT_MAP = '/cmd_object_map'
|
35
|
+
RUBYRUN_MONITOR_TIMER = 10
|
36
|
+
RUBYRUN_OUTPUT_PERF_SUMMARY = 'perf_summary'
|
37
|
+
RUBYRUN_OUTPUT_TXN_LOG = 'txn_log'
|
38
|
+
RUBYRUN_KILL_3_STRING = 'RUBYRUN kill -3'
|
39
|
+
RUBYRUN_OPTS_FILE = '/rubyrun_opts.yml'
|
40
|
+
RUBYRUN_PROP_DEFAULTS = {"APP_PATHS"=>[], "EXCLUDE_HASH"=>{}, "INCLUDE_HASH"=>{},
|
41
|
+
"DEBUG_ARGS"=>false, "DEBUG_OBJ"=>false, "DAD"=>false,
|
42
|
+
"REPORT_TIMER"=>60, "REPORT_SHIFT_AGE"=>60,
|
43
|
+
"OUTPUT" => ["#{RUBYRUN_OUTPUT_PERF_SUMMARY}","#{RUBYRUN_OUTPUT_TXN_LOG}","#{RUBYRUN_OUTPUT_PERF_SUMMARY}"],
|
44
|
+
"RSS_PATH" => nil, "TRACE_HASH"=>{}, "DB_ADAPTER_HASH"=>{}}
|
45
|
+
RUBYRUN_ACTIVERECORD = 'ActiveRecord::Base'
|
46
|
+
RUBYRUN_VIEW_HASH = {'ActionView::Base' => ['pick_template_extension','render_file']}
|
47
|
+
RUBYRUN_THREAD_END_HASH = {'WEBrick::HTTPServer' => ['run'], 'Mongrel::HttpServer' => ['process_client']}
|
48
|
+
RUBYRUN_OUTER_DISPATCH_HASH = {'Mongrel::Rails::RailsHandler' => ['process'], 'DispatchServlet' => ['service']}
|
49
|
+
RUBYRUN_INNER_DISPATCH_HASH = { 'Dispatcher' => ['dispatch'], 'ActionController::Dispatcher' => ['dispatch']}
|
50
|
+
|
51
|
+
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
|
@@ -0,0 +1,286 @@
|
|
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
|
+
# RubyRunInitializer__ sets up the environment for RubyRun. #
|
13
|
+
# The major task is to identify the application classes and #
|
14
|
+
# modules that are potential candidates for instrumentation. #
|
15
|
+
# #
|
16
|
+
# Also as at this release methods with super keyword is not #
|
17
|
+
# supported. These methods will need to be identified upfront. #
|
18
|
+
# #
|
19
|
+
#---------------------------------------------------------------#
|
20
|
+
module RubyRunInitializer__
|
21
|
+
|
22
|
+
require 'logger'
|
23
|
+
require 'yaml'
|
24
|
+
require 'digest/md5'
|
25
|
+
require 'rubyrun_globals'
|
26
|
+
require 'rubyrun_utils__'
|
27
|
+
include RubyRunGlobals
|
28
|
+
include RubyRunUtils__
|
29
|
+
|
30
|
+
# 1. Get all directories, logs and properties set up correctly
|
31
|
+
# 2. Scan files in APP_PATHS to create an initial INCLUDE_HASH
|
32
|
+
# and an EXCLUDE_HASH
|
33
|
+
def init_rubyrun
|
34
|
+
ready_rubyrun_env
|
35
|
+
discover_targets
|
36
|
+
end
|
37
|
+
|
38
|
+
# 1. Extract the working directory from ENV VAR and recursively create all the
|
39
|
+
# subdirectories if they dont exist
|
40
|
+
# 2. Create the log and trace folers
|
41
|
+
# 3. Initialize the loggers
|
42
|
+
# 4. Load the properties from either the current working directory or
|
43
|
+
# rubyrun working directory
|
44
|
+
# 5. Spawn a separate thread to for monitoring and commands
|
45
|
+
def ready_rubyrun_env
|
46
|
+
begin
|
47
|
+
raise RuntimeError, "environment variable #{RUBYRUN_WORKING_DIR} not set", caller \
|
48
|
+
unless env_var_exists?(RUBYRUN_WORKING_DIR)
|
49
|
+
rubyrun_working_dir = ENV[RUBYRUN_WORKING_DIR]
|
50
|
+
raise RuntimeError, "Missing #{RUBYRUN_OPTS_FILE} in #{rubyrun_working_dir}", caller \
|
51
|
+
unless File.exists?(rubyrun_working_dir + RUBYRUN_OPTS_FILE)
|
52
|
+
rescue Exception => e
|
53
|
+
fatal_exit(e)
|
54
|
+
end
|
55
|
+
*rubyrun_folders = rubyrun_working_dir + RUBYRUN_LOG, rubyrun_working_dir + RUBYRUN_REPORT, rubyrun_working_dir + RUBYRUN_SIGNATURE
|
56
|
+
make_folder(rubyrun_folders)
|
57
|
+
@rubyrun_log_folder, @rubyrun_report_folder, @rubyrun_signature_folder = *rubyrun_folders
|
58
|
+
logname = File.basename($0, ".*")
|
59
|
+
ready_logfile(logname)
|
60
|
+
system_wide_opts = rubyrun_working_dir + RUBYRUN_OPTS_FILE
|
61
|
+
app_wide_opts = Dir.getwd + '/' + RUBYRUN_OPTS_FILE
|
62
|
+
File.exists?(app_wide_opts) ? load_config_props(app_wide_opts) : load_config_props(system_wide_opts)
|
63
|
+
$rubyrun_tracer = RubyRunHTMLWriter.new(@rubyrun_report_folder + '/' + logname + '_' + $$.to_s + '_trace.html', METHOD_TRACE_HEADER, shift_age = 10, shift_size = 4096000) unless $rubyrun_trace_hash.empty?
|
64
|
+
end
|
65
|
+
|
66
|
+
# Make sub-directories (folders)
|
67
|
+
def make_folder(rubyrun_folders)
|
68
|
+
rubyrun_folders.each {|rubyrun_folder|
|
69
|
+
begin
|
70
|
+
Dir.mkdir(rubyrun_folder) unless File.exist?(rubyrun_folder)
|
71
|
+
rescue Exception => e
|
72
|
+
fatal_exit(e)
|
73
|
+
end
|
74
|
+
}
|
75
|
+
end
|
76
|
+
|
77
|
+
# Initialize rubyrun logger and create its own log format
|
78
|
+
def ready_logfile(logname)
|
79
|
+
$rubyrun_logger = Logger.new(@rubyrun_log_folder + '/' + logname + '_' + $$.to_s + '.log', shift_age = 10, shift_size = 4096000)
|
80
|
+
$rubyrun_logger.level = Logger::INFO
|
81
|
+
class << $rubyrun_logger
|
82
|
+
include RubyRunUtils__
|
83
|
+
def format_message (severity, timestamp, progname, msg)
|
84
|
+
"[#{timestamp.strftime("%Y-%m-%d %H:%M:%S")}.#{("%.3f" % timestamp.to_f).split('.')[1]}] #{get_thread_id} #{msg}\n"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Property file is a yml file.
|
90
|
+
# Load the properties into $config hash
|
91
|
+
def load_config_props(config_file)
|
92
|
+
begin
|
93
|
+
$rubyrun_config = YAML.load_file(config_file)
|
94
|
+
$rubyrun_logger.info "Properties found in #{config_file}:"
|
95
|
+
RUBYRUN_PROP_DEFAULTS.each {|prop, def_value|
|
96
|
+
$rubyrun_config[prop] = def_value unless config_prop_exists?(prop)
|
97
|
+
$rubyrun_logger.info "#{prop} = #{$rubyrun_config[prop].inspect}"
|
98
|
+
}
|
99
|
+
$rubyrun_logger.info "***** APP_PATHS is nil. Applications will not be instrumented. *****" \
|
100
|
+
if $rubyrun_config['APP_PATHS'].empty?
|
101
|
+
rescue Exception => e
|
102
|
+
fatal_exit(e)
|
103
|
+
end
|
104
|
+
$rubyrun_debug_args = $rubyrun_config['DEBUG_ARGS']
|
105
|
+
$rubyrun_debug_obj = $rubyrun_config['DEBUG_OBJ']
|
106
|
+
$rubyrun_dad = $rubyrun_config['DAD']
|
107
|
+
$rubyrun_report_timer = $rubyrun_config['REPORT_TIMER']
|
108
|
+
$rubyrun_report_shift_age = $rubyrun_config['REPORT_SHIFT_AGE']
|
109
|
+
$rubyrun_trace_hash = $rubyrun_config['TRACE_HASH']
|
110
|
+
$rubyrun_adapter_hash = $rubyrun_config['DB_ADAPTER_HASH']
|
111
|
+
validate_opts
|
112
|
+
end
|
113
|
+
|
114
|
+
# Validate the range of REPORT_TIMER and REPORT_SHIFT_AGE
|
115
|
+
# Use default values if out of acceptable range
|
116
|
+
def validate_opts
|
117
|
+
if $rubyrun_report_timer > 3600 || $rubyrun_report_timer < 60
|
118
|
+
$rubyrun_report_timer = RUBYRUN_PROP_DEFAULTS['REPORT_TIMER']
|
119
|
+
$rubyrun_logger.warn "REPORT_TIMER value must be between 60 and 3600. #{$rubyrun_report_timer}is used."
|
120
|
+
end
|
121
|
+
if $rubyrun_report_shift_age > 120 || $rubyrun_report_shift_age < 1
|
122
|
+
$rubyrun_report_shift_age = RUBYRUN_PROP_DEFAULTS['REPORT_SHIFT_AGE']
|
123
|
+
$rubyrun_logger.warn "REPORT_SHIFT_AGE value must be between 1 and 120. #{$rubyrun_report_shift_age}is used."
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# If the property is not defined or defined but with nil value, it
|
128
|
+
# is deemed to be non-existent
|
129
|
+
def config_prop_exists?(prop)
|
130
|
+
$rubyrun_config.has_key?(prop) && !$rubyrun_config[prop].nil? ? true : false
|
131
|
+
end
|
132
|
+
|
133
|
+
# Set up global variables from the property file rubyrun_config.yml
|
134
|
+
# For APP_PATHS property, expand any subdirectories and look for
|
135
|
+
# .rb files recursively
|
136
|
+
def discover_targets
|
137
|
+
identify_candidates
|
138
|
+
$rubyrun_include_hash.merge!($rubyrun_config['INCLUDE_HASH'])
|
139
|
+
['DB_ADAPTER_HASH','OUTER_DISPATCH_HASH','INNER_DISPATCH_HASH'].each { |hash_key|
|
140
|
+
$rubyrun_include_hash.merge!($rubyrun_config[hash_key]) { |k,o,n| o.concat(n) } if config_prop_exists?(hash_key)
|
141
|
+
}
|
142
|
+
[RUBYRUN_OUTER_DISPATCH_HASH,RUBYRUN_INNER_DISPATCH_HASH,RUBYRUN_THREAD_END_HASH,RUBYRUN_VIEW_HASH].each {|hash|
|
143
|
+
$rubyrun_include_hash.merge!(hash) { |k,o,n| o.concat(n) }
|
144
|
+
}
|
145
|
+
$rubyrun_exclude_hash.merge!($rubyrun_config['EXCLUDE_HASH'])
|
146
|
+
$rubyrun_outer_dispatch_hash = config_prop_exists?('OUTER_DISPATCH_HASH') ? RUBYRUN_OUTER_DISPATCH_HASH.merge($rubyrun_config['OUTER_DISPATCH_HASH']) : RUBYRUN_OUTER_DISPATCH_HASH
|
147
|
+
$rubyrun_inner_dispatch_hash = config_prop_exists?('INNER_DISPATCH_HASH') ? RUBYRUN_INNER_DISPATCH_HASH.merge($rubyrun_config['INNER_DISPATCH_HASH']) : RUBYRUN_INNER_DISPATCH_HASH
|
148
|
+
$rubyrun_logger.info "Final INCLUDE_HASH = #{$rubyrun_include_hash.inspect}"
|
149
|
+
$rubyrun_logger.info "Final EXCLUDE_HASH = #{$rubyrun_exclude_hash.inspect}"
|
150
|
+
end
|
151
|
+
|
152
|
+
# If the directory content has changed (new files, modified files,
|
153
|
+
# new APP_PATHS) a new scan will be required, otherwise the last scan
|
154
|
+
# results will simply be reused. When a new scan is finished,
|
155
|
+
# the results are serialized.
|
156
|
+
#
|
157
|
+
# Digest technique is used to detect changes in directory content.
|
158
|
+
def identify_candidates
|
159
|
+
$rubyrun_config['APP_PATHS'].each {|element|
|
160
|
+
element = Dir.getwd if element == '.'
|
161
|
+
expand_folder(element)
|
162
|
+
}
|
163
|
+
unless $rubyrun_file_date_hash.empty?
|
164
|
+
dir_signature = generate_hash($rubyrun_file_date_hash)
|
165
|
+
exclude_array = []
|
166
|
+
if directory_changed?(dir_signature)
|
167
|
+
$rubyrun_file_date_hash.each {|f, date|
|
168
|
+
scan_module_class(f)
|
169
|
+
scan_super(f).each {|name| exclude_array << name}
|
170
|
+
}
|
171
|
+
$rubyrun_exclude_hash['*'] = exclude_array.uniq if exclude_array.length > 0
|
172
|
+
serialize_scan_history(dir_signature)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
deserialize_scan_history
|
176
|
+
$rubyrun_file_date_hash.clear if $rubyrun_file_date_hash
|
177
|
+
end
|
178
|
+
|
179
|
+
# For each directory, expand into a list of filenames and its modifed time.
|
180
|
+
def expand_folder(folder)
|
181
|
+
($rubyrun_logger.warn("WARN: APP_PATHS not found: #{folder}") ; return) unless File.exists?(folder)
|
182
|
+
if File.file?(folder)
|
183
|
+
return if File.extname(folder) != '.rb'
|
184
|
+
path = File.expand_path(folder)
|
185
|
+
$rubyrun_file_date_hash[path] = File.mtime(path).to_i
|
186
|
+
else
|
187
|
+
Dir.entries(folder).each {|entry|
|
188
|
+
next if entry =~ /^\.+/
|
189
|
+
path = File.expand_path(entry, folder)
|
190
|
+
case
|
191
|
+
when File.directory?(path)
|
192
|
+
expand_folder(path)
|
193
|
+
else
|
194
|
+
next if File.extname(entry) != '.rb'
|
195
|
+
$rubyrun_file_date_hash[path] = File.mtime(path).to_i
|
196
|
+
end
|
197
|
+
}
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
# Compare the digest calculated from the current APP_PATHS directory
|
202
|
+
# contents to the last serialized one. Return true(changed) or false
|
203
|
+
# (unchanged)
|
204
|
+
def directory_changed?(dir_signature)
|
205
|
+
f = get_dir_hash_file
|
206
|
+
dir_sig = File.exists?(f) ? File.open(f) {|f| Marshal.load(f)} : nil
|
207
|
+
dir_signature != dir_sig
|
208
|
+
end
|
209
|
+
|
210
|
+
# Calcualte the digest from the directory contents of APP_PATHS
|
211
|
+
def generate_hash(hash)
|
212
|
+
Digest::MD5.hexdigest(hash.to_s)
|
213
|
+
end
|
214
|
+
|
215
|
+
# Use Marshal to serialize scan results (the include and exclude hashes)
|
216
|
+
def serialize_scan_history(dir_signature)
|
217
|
+
File.open(get_include_hash_file, 'w') {|f| Marshal.dump($rubyrun_include_hash, f)}
|
218
|
+
File.open(get_exclude_hash_file, 'w') {|f| Marshal.dump($rubyrun_exclude_hash, f)}
|
219
|
+
File.open(get_dir_hash_file, 'w') {|f| Marshal.dump(dir_signature, f)}
|
220
|
+
end
|
221
|
+
|
222
|
+
# Use Marshal to de-serialize the include and exclude hashes
|
223
|
+
def deserialize_scan_history
|
224
|
+
f = get_include_hash_file
|
225
|
+
$rubyrun_include_hash = File.exists?(f) ? File.open(f) {|f| Marshal.load(f)} : {}
|
226
|
+
f = get_exclude_hash_file
|
227
|
+
$rubyrun_exclude_hash = File.exists?(f) ? File.open(f) {|f| Marshal.load(f)} : {}
|
228
|
+
end
|
229
|
+
|
230
|
+
# Regular expression that detects the class or module names of a given file
|
231
|
+
def scan_module_class(path)
|
232
|
+
$rubyrun_logger.info "Candidate modules/classes for instrumentation in #{path}:"
|
233
|
+
open(path).grep(/^\s*(class|module)\s+([[:upper:]][A-Za-z0-9_:]*)/m) {
|
234
|
+
$rubyrun_logger.info "\t #{$2}"
|
235
|
+
$rubyrun_include_hash[$2] = []
|
236
|
+
}
|
237
|
+
end
|
238
|
+
|
239
|
+
# Line up all the method names in a file by line #
|
240
|
+
# Line up all the line numbers that contain the keyworkd super
|
241
|
+
# Collate the two arrays to determine which method has super in it
|
242
|
+
# Put these method names in EXCLUDE_HASH and skip instrumentation
|
243
|
+
def scan_super(path)
|
244
|
+
$rubyrun_logger.info "Method(s) to be excluded from instrumentation in #{path}:"
|
245
|
+
method_name_array, method_lineno_array, super_array, exclude_array = [],[],[],[]
|
246
|
+
open(path) {|f|
|
247
|
+
f.readlines.each_with_index {|code, lineno|
|
248
|
+
code.scan(/^\s*def\s+(.*)\(+.*\)+/m)
|
249
|
+
(method_name_array << $1; method_lineno_array << lineno) if $1
|
250
|
+
code.scan(/^\s*(super)/m)
|
251
|
+
super_array << lineno if $1
|
252
|
+
}
|
253
|
+
}
|
254
|
+
method_name_array.reverse!
|
255
|
+
method_lineno_array.reverse!
|
256
|
+
super_array.each {|lineno|
|
257
|
+
method_lineno_array.each_with_index {|linenum, i|
|
258
|
+
unless lineno < linenum
|
259
|
+
$rubyrun_logger.info "\t #{method_name_array[i]}"
|
260
|
+
m = method_name_array[i].split('.')
|
261
|
+
exclude_array << (m.length > 1 ? m[1] : m[0])
|
262
|
+
break
|
263
|
+
end
|
264
|
+
}
|
265
|
+
}
|
266
|
+
exclude_array
|
267
|
+
end
|
268
|
+
|
269
|
+
# Return the target file name that stores the serialized INCLUDE_HASH
|
270
|
+
def get_include_hash_file
|
271
|
+
@rubyrun_signature_folder + '/' + RUBYRUN_INCLUDE_HASH_FILE
|
272
|
+
end
|
273
|
+
|
274
|
+
# return the target file name that stores the serialized EXCLUDE_HASH
|
275
|
+
def get_exclude_hash_file
|
276
|
+
@rubyrun_signature_folder + '/' + RUBYRUN_EXCLUDE_HASH_FILE
|
277
|
+
end
|
278
|
+
|
279
|
+
# Return the target file name that stores the serialized directory contents digest
|
280
|
+
# This file has to be application dependent, and we use the current directory of the
|
281
|
+
# running process to represent the application directory.
|
282
|
+
def get_dir_hash_file
|
283
|
+
@rubyrun_signature_folder + '/' + RUBYRUN_DIR_HASH_FILE + '_' + Digest::MD5.hexdigest(Dir.getwd)
|
284
|
+
end
|
285
|
+
|
286
|
+
end
|