RubyRun_CE 0.9.0-powerpc-darwin

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. data/LICENSE +13 -0
  2. data/README +75 -0
  3. data/Rakefile +241 -0
  4. data/bin/confgure +2 -0
  5. data/docs/RubyRunCE_09.htm +6346 -0
  6. data/docs/RubyRunCE_09.pdf +0 -0
  7. data/docs/RubyRunCE_09_files/colorschememapping.xml +2 -0
  8. data/docs/RubyRunCE_09_files/filelist.xml +29 -0
  9. data/docs/RubyRunCE_09_files/header.htm +142 -0
  10. data/docs/RubyRunCE_09_files/image001.jpg +0 -0
  11. data/docs/RubyRunCE_09_files/image002.jpg +0 -0
  12. data/docs/RubyRunCE_09_files/image003.jpg +0 -0
  13. data/docs/RubyRunCE_09_files/image004.jpg +0 -0
  14. data/docs/RubyRunCE_09_files/image005.jpg +0 -0
  15. data/docs/RubyRunCE_09_files/image006.jpg +0 -0
  16. data/docs/RubyRunCE_09_files/image007.jpg +0 -0
  17. data/docs/RubyRunCE_09_files/image008.jpg +0 -0
  18. data/docs/RubyRunCE_09_files/image009.jpg +0 -0
  19. data/docs/RubyRunCE_09_files/image010.jpg +0 -0
  20. data/docs/RubyRunCE_09_files/image011.jpg +0 -0
  21. data/docs/RubyRunCE_09_files/image012.jpg +0 -0
  22. data/docs/RubyRunCE_09_files/image013.jpg +0 -0
  23. data/docs/RubyRunCE_09_files/image014.jpg +0 -0
  24. data/docs/RubyRunCE_09_files/image015.jpg +0 -0
  25. data/docs/RubyRunCE_09_files/image016.jpg +0 -0
  26. data/docs/RubyRunCE_09_files/image017.png +0 -0
  27. data/docs/RubyRunCE_09_files/image018.jpg +0 -0
  28. data/docs/RubyRunCE_09_files/image019.jpg +0 -0
  29. data/docs/RubyRunCE_09_files/image020.jpg +0 -0
  30. data/docs/RubyRunCE_09_files/image021.jpg +0 -0
  31. data/docs/RubyRunCE_09_files/image022.png +0 -0
  32. data/docs/RubyRunCE_09_files/themedata.thmx +0 -0
  33. data/etc/rubyrun_opts.yml +132 -0
  34. data/ext/extconf.rb +4 -0
  35. data/ext/rubyrunnative__.bundle +0 -0
  36. data/ext/rubyrunnative__.c +154 -0
  37. data/ext/rubyrunnative__.def +2 -0
  38. data/ext/rubyrunnative__.h +36 -0
  39. data/ext/rubyrunnative__.so +0 -0
  40. data/ext/rubyrunnative__linux.so +0 -0
  41. data/html/classes/Module.html +174 -0
  42. data/html/classes/Object.html +151 -0
  43. data/html/classes/RubyRunBufferMgr__.html +182 -0
  44. data/html/classes/RubyRunCommander__.html +578 -0
  45. data/html/classes/RubyRunDad__.html +144 -0
  46. data/html/classes/RubyRunGlobals.html +248 -0
  47. data/html/classes/RubyRunHTMLWriter.html +186 -0
  48. data/html/classes/RubyRunHTMLWriter/RubyRunHTMLDevice.html +157 -0
  49. data/html/classes/RubyRunHTML__.html +198 -0
  50. data/html/classes/RubyRunInitializer__.html +821 -0
  51. data/html/classes/RubyRunInstrumentor__.html +576 -0
  52. data/html/classes/RubyRunMonitor__.html +298 -0
  53. data/html/classes/RubyRunRSS.html +302 -0
  54. data/html/classes/RubyRunReport__.html +294 -0
  55. data/html/classes/RubyRunTracer__.html +253 -0
  56. data/html/classes/RubyRunUtils__.html +376 -0
  57. data/html/created.rid +1 -0
  58. data/html/files/LICENSE.html +119 -0
  59. data/html/files/README.html +196 -0
  60. data/html/files/lib/rubyrun/rubyrun_buffer_mgr___rb.html +101 -0
  61. data/html/files/lib/rubyrun/rubyrun_commander___rb.html +101 -0
  62. data/html/files/lib/rubyrun/rubyrun_dad___rb.html +101 -0
  63. data/html/files/lib/rubyrun/rubyrun_globals_rb.html +101 -0
  64. data/html/files/lib/rubyrun/rubyrun_html___rb.html +101 -0
  65. data/html/files/lib/rubyrun/rubyrun_html_writer___rb.html +108 -0
  66. data/html/files/lib/rubyrun/rubyrun_initializer___rb.html +112 -0
  67. data/html/files/lib/rubyrun/rubyrun_instrumentor___rb.html +116 -0
  68. data/html/files/lib/rubyrun/rubyrun_monitor___rb.html +116 -0
  69. data/html/files/lib/rubyrun/rubyrun_rb.html +121 -0
  70. data/html/files/lib/rubyrun/rubyrun_report___rb.html +101 -0
  71. data/html/files/lib/rubyrun/rubyrun_rss___rb.html +108 -0
  72. data/html/files/lib/rubyrun/rubyrun_tracer___rb.html +110 -0
  73. data/html/files/lib/rubyrun/rubyrun_utils___rb.html +108 -0
  74. data/html/files/lib/rubyrunm_rb.html +116 -0
  75. data/html/fr_class_index.html +42 -0
  76. data/html/fr_file_index.html +43 -0
  77. data/html/fr_method_index.html +96 -0
  78. data/html/index.html +24 -0
  79. data/html/rdoc-style.css +208 -0
  80. data/lib/rubyrun/rubyrun.rb +78 -0
  81. data/lib/rubyrun/rubyrun_buffer_mgr__.rb +49 -0
  82. data/lib/rubyrun/rubyrun_commander__.rb +196 -0
  83. data/lib/rubyrun/rubyrun_dad__.rb +35 -0
  84. data/lib/rubyrun/rubyrun_globals.rb +51 -0
  85. data/lib/rubyrun/rubyrun_html__.rb +136 -0
  86. data/lib/rubyrun/rubyrun_html_writer__.rb +64 -0
  87. data/lib/rubyrun/rubyrun_initializer__.rb +286 -0
  88. data/lib/rubyrun/rubyrun_instrumentor__.rb +226 -0
  89. data/lib/rubyrun/rubyrun_monitor__.rb +237 -0
  90. data/lib/rubyrun/rubyrun_report__.rb +109 -0
  91. data/lib/rubyrun/rubyrun_rss__.rb +97 -0
  92. data/lib/rubyrun/rubyrun_tracer__.rb +79 -0
  93. data/lib/rubyrun/rubyrun_utils__.rb +98 -0
  94. data/lib/rubyrun/rubyrunnative__.bundle +0 -0
  95. data/lib/rubyrunm.rb +10 -0
  96. 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>&nbsp;</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