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.
Files changed (96) hide show
  1. data/LICENSE +13 -0
  2. data/README +77 -0
  3. data/Rakefile +241 -0
  4. data/bin/confgure +2 -0
  5. data/docs/rubyrun-0.9.0.htm +6344 -0
  6. data/docs/rubyrun-0.9.0.pdf +0 -0
  7. data/docs/rubyrun-0.9.0_files/colorschememapping.xml +2 -0
  8. data/docs/rubyrun-0.9.0_files/filelist.xml +29 -0
  9. data/docs/rubyrun-0.9.0_files/header.htm +141 -0
  10. data/docs/rubyrun-0.9.0_files/image001.jpg +0 -0
  11. data/docs/rubyrun-0.9.0_files/image002.jpg +0 -0
  12. data/docs/rubyrun-0.9.0_files/image003.jpg +0 -0
  13. data/docs/rubyrun-0.9.0_files/image004.jpg +0 -0
  14. data/docs/rubyrun-0.9.0_files/image005.jpg +0 -0
  15. data/docs/rubyrun-0.9.0_files/image006.jpg +0 -0
  16. data/docs/rubyrun-0.9.0_files/image007.jpg +0 -0
  17. data/docs/rubyrun-0.9.0_files/image008.jpg +0 -0
  18. data/docs/rubyrun-0.9.0_files/image009.jpg +0 -0
  19. data/docs/rubyrun-0.9.0_files/image010.jpg +0 -0
  20. data/docs/rubyrun-0.9.0_files/image011.jpg +0 -0
  21. data/docs/rubyrun-0.9.0_files/image012.jpg +0 -0
  22. data/docs/rubyrun-0.9.0_files/image013.jpg +0 -0
  23. data/docs/rubyrun-0.9.0_files/image014.jpg +0 -0
  24. data/docs/rubyrun-0.9.0_files/image015.jpg +0 -0
  25. data/docs/rubyrun-0.9.0_files/image016.jpg +0 -0
  26. data/docs/rubyrun-0.9.0_files/image017.png +0 -0
  27. data/docs/rubyrun-0.9.0_files/image018.jpg +0 -0
  28. data/docs/rubyrun-0.9.0_files/image019.jpg +0 -0
  29. data/docs/rubyrun-0.9.0_files/image020.jpg +0 -0
  30. data/docs/rubyrun-0.9.0_files/image021.jpg +0 -0
  31. data/docs/rubyrun-0.9.0_files/image022.png +0 -0
  32. data/docs/rubyrun-0.9.0_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/RubyRunHTMLDevice.html +157 -0
  48. data/html/classes/RubyRunHTMLWriter.html +186 -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 +197 -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__.so +0 -0
  95. data/lib/rubyrunm.rb +10 -0
  96. 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>&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