rubyrun 0.9.0-mswin32
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/Rakefile +241 -0
- data/bin/confgure +2 -0
- data/docs/rubyrun-0.9.0.htm +6344 -0
- data/docs/rubyrun-0.9.0.pdf +0 -0
- data/docs/rubyrun-0.9.0_files/colorschememapping.xml +2 -0
- data/docs/rubyrun-0.9.0_files/filelist.xml +29 -0
- data/docs/rubyrun-0.9.0_files/header.htm +141 -0
- data/docs/rubyrun-0.9.0_files/image001.jpg +0 -0
- data/docs/rubyrun-0.9.0_files/image002.jpg +0 -0
- data/docs/rubyrun-0.9.0_files/image003.jpg +0 -0
- data/docs/rubyrun-0.9.0_files/image004.jpg +0 -0
- data/docs/rubyrun-0.9.0_files/image005.jpg +0 -0
- data/docs/rubyrun-0.9.0_files/image006.jpg +0 -0
- data/docs/rubyrun-0.9.0_files/image007.jpg +0 -0
- data/docs/rubyrun-0.9.0_files/image008.jpg +0 -0
- data/docs/rubyrun-0.9.0_files/image009.jpg +0 -0
- data/docs/rubyrun-0.9.0_files/image010.jpg +0 -0
- data/docs/rubyrun-0.9.0_files/image011.jpg +0 -0
- data/docs/rubyrun-0.9.0_files/image012.jpg +0 -0
- data/docs/rubyrun-0.9.0_files/image013.jpg +0 -0
- data/docs/rubyrun-0.9.0_files/image014.jpg +0 -0
- data/docs/rubyrun-0.9.0_files/image015.jpg +0 -0
- data/docs/rubyrun-0.9.0_files/image016.jpg +0 -0
- data/docs/rubyrun-0.9.0_files/image017.png +0 -0
- data/docs/rubyrun-0.9.0_files/image018.jpg +0 -0
- data/docs/rubyrun-0.9.0_files/image019.jpg +0 -0
- data/docs/rubyrun-0.9.0_files/image020.jpg +0 -0
- data/docs/rubyrun-0.9.0_files/image021.jpg +0 -0
- data/docs/rubyrun-0.9.0_files/image022.png +0 -0
- data/docs/rubyrun-0.9.0_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/RubyRunHTMLDevice.html +157 -0
- data/html/classes/RubyRunHTMLWriter.html +186 -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 +197 -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__.so +0 -0
- data/lib/rubyrunm.rb +10 -0
- metadata +149 -0
@@ -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
|