rubyrun 0.9.5-x86-mswin32-60

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. data/LICENSE +13 -0
  2. data/README +77 -0
  3. data/bin/Rakefile +11 -0
  4. data/docs/rubyrun-0.9.5.htm +5937 -0
  5. data/docs/rubyrun-0.9.5.pdf +0 -0
  6. data/docs/rubyrun-0.9.5_files/colorschememapping.xml +2 -0
  7. data/docs/rubyrun-0.9.5_files/filelist.xml +29 -0
  8. data/docs/rubyrun-0.9.5_files/header.htm +138 -0
  9. data/docs/rubyrun-0.9.5_files/image001.jpg +0 -0
  10. data/docs/rubyrun-0.9.5_files/image002.jpg +0 -0
  11. data/docs/rubyrun-0.9.5_files/image003.jpg +0 -0
  12. data/docs/rubyrun-0.9.5_files/image004.jpg +0 -0
  13. data/docs/rubyrun-0.9.5_files/image005.jpg +0 -0
  14. data/docs/rubyrun-0.9.5_files/image006.jpg +0 -0
  15. data/docs/rubyrun-0.9.5_files/image007.jpg +0 -0
  16. data/docs/rubyrun-0.9.5_files/image008.jpg +0 -0
  17. data/docs/rubyrun-0.9.5_files/image009.jpg +0 -0
  18. data/docs/rubyrun-0.9.5_files/image010.jpg +0 -0
  19. data/docs/rubyrun-0.9.5_files/image011.jpg +0 -0
  20. data/docs/rubyrun-0.9.5_files/image012.jpg +0 -0
  21. data/docs/rubyrun-0.9.5_files/image013.jpg +0 -0
  22. data/docs/rubyrun-0.9.5_files/image014.jpg +0 -0
  23. data/docs/rubyrun-0.9.5_files/image015.jpg +0 -0
  24. data/docs/rubyrun-0.9.5_files/image016.jpg +0 -0
  25. data/docs/rubyrun-0.9.5_files/image017.png +0 -0
  26. data/docs/rubyrun-0.9.5_files/image018.jpg +0 -0
  27. data/docs/rubyrun-0.9.5_files/image019.jpg +0 -0
  28. data/docs/rubyrun-0.9.5_files/image020.jpg +0 -0
  29. data/docs/rubyrun-0.9.5_files/image021.jpg +0 -0
  30. data/docs/rubyrun-0.9.5_files/image022.png +0 -0
  31. data/docs/rubyrun-0.9.5_files/themedata.thmx +0 -0
  32. data/etc/rubyrun_opts.yml +132 -0
  33. data/ext/extconf.rb +5 -0
  34. data/ext/rubyrunnative__.c +154 -0
  35. data/ext/rubyrunnative__.def +2 -0
  36. data/ext/rubyrunnative__.h +36 -0
  37. data/ext/rubyrunnative__ppc-darwin.bundle +0 -0
  38. data/ext/rubyrunnative__x86-darwin.bundle +0 -0
  39. data/ext/rubyrunnative__x86-linux.so +0 -0
  40. data/ext/rubyrunnative__x86-mswin32.so +0 -0
  41. data/lib/rubyrun/rubyrun.rb +2 -0
  42. data/lib/rubyrun/rubyrun_boot__.rb +79 -0
  43. data/lib/rubyrun/rubyrun_buffer_mgr__.rb +49 -0
  44. data/lib/rubyrun/rubyrun_commander__.rb +196 -0
  45. data/lib/rubyrun/rubyrun_dad__.rb +35 -0
  46. data/lib/rubyrun/rubyrun_globals.rb +52 -0
  47. data/lib/rubyrun/rubyrun_html__.rb +136 -0
  48. data/lib/rubyrun/rubyrun_html_writer__.rb +64 -0
  49. data/lib/rubyrun/rubyrun_initializer__.rb +313 -0
  50. data/lib/rubyrun/rubyrun_instrumentor__.rb +226 -0
  51. data/lib/rubyrun/rubyrun_monitor__.rb +238 -0
  52. data/lib/rubyrun/rubyrun_report__.rb +109 -0
  53. data/lib/rubyrun/rubyrun_rss__.rb +97 -0
  54. data/lib/rubyrun/rubyrun_tracer__.rb +79 -0
  55. data/lib/rubyrun/rubyrun_utils__.rb +101 -0
  56. data/lib/rubyrun/rubyrunnative__.so +0 -0
  57. metadata +115 -0
@@ -0,0 +1,49 @@
1
+ #--------------------------------------------------------------------#
2
+ # #
3
+ # (C) Copyright Rubysophic Inc. 2007-2008 #
4
+ # All rights reserved. #
5
+ # #
6
+ # Use, duplication or disclosure of the code is not permitted #
7
+ # unless licensed. #
8
+ # #
9
+ # Last Updated: 7/09/08 #
10
+ #--------------------------------------------------------------------#
11
+ # #
12
+ # RubyRunBufferMgr__ module is responsible for passing the data #
13
+ # from the inline execution thread to the monitor thread #
14
+ # #
15
+ # Two buffers (primary and secondary) are used and the buffers are #
16
+ # swapped between the inline execution thread and RubyRunMonitor__ #
17
+ # thread periodically as defined by REPORT_TIMER. The inline #
18
+ # execution thread pushes data into the primary buffer, when the #
19
+ # REPORT_TIMER expires, RubyRunMonitor__ thread then takes it over #
20
+ # and gives the inline execution thread the secondary buffer via #
21
+ # a quick swap. The same process keeps repeating as the monitor #
22
+ # timer pops and the primary and secondary keep switched between #
23
+ # the two threads. #
24
+ # #
25
+ #--------------------------------------------------------------------#
26
+ module RubyRunBufferMgr__
27
+
28
+ # Push data into the current buffer
29
+ # Primary or secondary buffer may be used but it is transparent to the caller
30
+ def push_current_buffer(metrics)
31
+ $rubyrun_lock.synchronize {
32
+ ($rubyrun_current_buffer == 1 ? $rubyrun_prime_buffer : $rubyrun_alt_buffer) << metrics
33
+ }
34
+ end
35
+
36
+ # Return the current buffer and swap it with the other one
37
+ # This method is invoked by the consumer of the data in the buffer
38
+ def return_and_switch_buffer()
39
+ $rubyrun_lock.synchronize {
40
+ if ($rubyrun_current_buffer == 1)
41
+ $rubyrun_current_buffer == 2
42
+ $rubyrun_prime_buffer
43
+ else
44
+ $rubyrun_current_buffer == 1
45
+ $rubyrun_alt_buffer
46
+ end
47
+ }
48
+ end
49
+ end
@@ -0,0 +1,196 @@
1
+ #-----------------------------------------------------------------#
2
+ # #
3
+ # (C) Copyright Rubysophic Inc. 2007-2008 #
4
+ # All rights reserved. #
5
+ # #
6
+ # Use, duplication or disclosure of the code is not permitted #
7
+ # unless licensed. #
8
+ # #
9
+ # Last Updated: 7/18/08 #
10
+ #-----------------------------------------------------------------#
11
+ # #
12
+ # RubyRunCommander__ is a module which handles the commands #
13
+ # cmd_status, cmd_object_map, cmd_soft_kill and cmd_hard_kill #
14
+ # #
15
+ #-----------------------------------------------------------------#
16
+ module RubyRunCommander__
17
+
18
+ # Use Thread.list to list show thread status, and native code to
19
+ # display the last line # and function of the threads
20
+ def dump_thread_status
21
+ (unsupport_function; return) unless $rubyrun_native
22
+ $rubyrun_thread_status_reporter = RubyRunHTMLWriter.new(@rubyrun_report_folder + '/' + File.basename($0, ".*") + '_' + $$.to_s + '_thread_status.html', nil, shift_age = 10, shift_size = 4096000) unless $rubyrun_thread_status_reporter
23
+ start_time = Time.now
24
+ th_data_hash = RubyRunNative__.get_all_top_stacks
25
+ odd_row ||= true
26
+ table_content = ''
27
+ Thread.list.each {|th|
28
+ thread_id = get_thread_id(th)
29
+ table_content += sprintf("#{odd_row ? THREAD_STATUS_ODD_ROW : THREAD_STATUS_EVEN_ROW}",
30
+ thread_id, th.status, get_top_stack(th_data_hash, thread_id))
31
+ odd_row = !odd_row
32
+ }
33
+ html_content = THREAD_STATUS_HTML.sub(/%START_TIMESTAMP%/,start_time.strftime("%H:%M:%S %m/%d/%Y"))
34
+ html_content.sub!(/%THREAD_STATUS_ROW%/,table_content)
35
+ $rubyrun_thread_status_reporter.info(html_content)
36
+ end
37
+
38
+ # Dump Controller/Actions response time metrics
39
+ # metrics structure
40
+ # metrics[0] Thread ID metrics[1] Timestamp of the request
41
+ # metrics[2] URL metrics[3] Controller name
42
+ # metrics[4] Action name metrics[5] Response time
43
+ # metrics[6] Action time metrics[7] Database IO time
44
+ # metrics[8] View time metrics[9] Uncaptured time
45
+ # metrics[10] Dispatch wait time
46
+ def dump_reports(dump_all_reports = false)
47
+ buffer = return_and_switch_buffer
48
+ buffer.each { |metrics|
49
+ # Last element is 1, representing a request count of 1, used for calculating average response time for this controller/action
50
+ update_perf_metrics(metrics[3], {metrics[4] => [metrics[5],metrics[6],metrics[7],metrics[8],metrics[9],metrics[10],1]})
51
+ }
52
+ @rubyrun_req_count ||= 0
53
+ @rubyrun_req_count += buffer.length
54
+ if $rubyrun_config['OUTPUT'].include?(RUBYRUN_OUTPUT_PERF_SUMMARY) && dump_all_reports
55
+ create_rss_channels if (!$rubyrun_perf_summary_rss && $rubyrun_rails_env)
56
+ add_perf_summary_rss_item(@rubyrun_req_count)
57
+ @rubyrun_req_count = 0
58
+ end
59
+ if $rubyrun_config['OUTPUT'].include?(RUBYRUN_OUTPUT_TXN_LOG)
60
+ create_csv_files unless $rubyrun_txn_log_reporter
61
+ add_txn_log_csv_item(buffer)
62
+ end
63
+ buffer.clear # Clear the buffer so that the main thread will push the data into a blank bucket
64
+ end
65
+
66
+ # The way to do soft/hard kill is to performa a thr.raise on the thread
67
+ # from the thread monitor. Using the begin/rescue created around the block
68
+ # in Thread.new by RubyRunInstrumentor__, the raise will be rescued
69
+ # and $@ is then extracted to a global hash.
70
+ # Softkill only kills non-main threads. Hardkill kills the main thread also
71
+ # but as the last step.
72
+ def kill_threads(monitor_thr)
73
+ (unsupport_function; return) unless $rubyrun_native
74
+ if !$rubyrun_thread_dump_reporter
75
+ $rubyrun_thread_dump_reporter = Logger.new(@rubyrun_report_folder + '/' + File.basename($0, ".*") + '_' + $$.to_s + '_thread_dump.txt', shift_age = 10, shift_size = 4096000)
76
+ $rubyrun_thread_dump_reporter.level = Logger::INFO
77
+ class << $rubyrun_thread_dump_reporter
78
+ include RubyRunUtils__
79
+ def format_message (severity, timestamp, progname, msg)
80
+ "[#{timestamp.strftime("%Y-%m-%d %H:%M:%S")}.#{("%.3f" % timestamp.to_f).split('.')[1]}] #{get_thread_id} #{msg}\n"
81
+ end
82
+ end
83
+ end
84
+ th_data_hash = RubyRunNative__.get_all_top_stacks
85
+ j_th_id = return_joined_thread(th_data_hash)
86
+ Thread.list.each {|th|
87
+ th_id = get_thread_id(th)
88
+ if th.status == 'sleep' && th_id != get_thread_id && th_id != get_thread_id(monitor_thr) &&
89
+ th_id != get_thread_id(Thread.main) && th_id != j_th_id
90
+ $rubyrun_thread_dump_reporter.info "*** Raising exception #{RUBYRUN_KILL_3_STRING} to #{get_thread_id(th)} ***"
91
+ th.raise ThreadError, RUBYRUN_KILL_3_STRING
92
+ end
93
+ }
94
+ sleep 3
95
+ back_trace_all(th_data_hash)
96
+ hard_kill = hard_kill?
97
+ remove_cmd_folder
98
+ Thread.main.raise ThreadError, RUBYRUN_KILL_3_STRING if hard_kill
99
+ end
100
+
101
+ # Show the top 20 Ruby classes which have the largest no. of instances in memory
102
+ # The snapshot is taken after a gc call is made
103
+ def dump_object_map
104
+ start_time = Time.now
105
+ $rubyrun_obj_map_reporter = RubyRunHTMLWriter.new(@rubyrun_report_folder + '/' + File.basename($0, ".*") + '_' + $$.to_s + '_object_map.html', nil, shift_age = 10, shift_size = 4096000) unless $rubyrun_obj_map_reporter
106
+ object_map = Hash.new
107
+ ttl_object = 0
108
+ ObjectSpace.garbage_collect
109
+ ObjectSpace.each_object { |obj|
110
+ ttl_object += 1
111
+ object_map.has_key?(obj.class) ? object_map[obj.class] += 1 : object_map[obj.class] = 1
112
+ }
113
+ results = object_map.sort{|a,b| a[1]<=>b[1]}.reverse!
114
+ table_content = ''
115
+ odd_row ||=true
116
+ 20.times {|i|
117
+ table_content += sprintf("#{odd_row ? OBJ_MAP_ODD_ROW : OBJ_MAP_EVEN_ROW}",
118
+ results[i][0], results[i][1].to_s)
119
+ odd_row = !odd_row
120
+ }
121
+ html_content = OBJ_MAP_HTML.sub(/%START_TIMESTAMP%/,start_time.strftime("%H:%M:%S %m/%d/%Y"))
122
+ html_content.sub!(/%OBJ_MAP_ROW%/,table_content)
123
+ $rubyrun_obj_map_reporter.info(html_content)
124
+ end
125
+
126
+ # metrics hash is a global collection point for all metrics (averaged)
127
+ # for all actions by controller
128
+ # Use serialization before updating this global hash
129
+ # Structure of $rubyrun_metrics_hash:
130
+ # controller_name => {action_name => [response_time, action_time,
131
+ # db_io_time, view_time,
132
+ # uncaptured_time, dispatch_wait_time,
133
+ # request_count]}
134
+ def update_perf_metrics(controller, action_metrics_hash)
135
+ $rubyrun_metrics_hash[controller].merge!(action_metrics_hash) {|action, o_metrics, new_metrics|
136
+ o_metrics.each_index { |x|
137
+ (o_metrics[x] += new_metrics[x]; break) if x == (o_metrics.length-1) # Calculate the total request count for this controller/action
138
+ o_metrics[x] = (o_metrics[x] * o_metrics.last + new_metrics[x])/(o_metrics.last + new_metrics.last).to_f
139
+ }
140
+ o_metrics
141
+ }
142
+ end
143
+
144
+ # If a thread is joined this method returns the joining thread ID
145
+ def return_joined_thread(th_data_hash)
146
+ th_data_hash.each {|th, top_stack|
147
+ if th.to_s.include?(get_thread_id(Thread.main))
148
+ top_stack[0] =~ /\*\*(.+?)\*\*/
149
+ return $1
150
+ end
151
+ }
152
+ end
153
+
154
+ # Remove the cmd_kill-3 folder or file if any
155
+ def remove_cmd_folder
156
+ [RUBYRUN_CMD_SOFT_KILL, RUBYRUN_CMD_HARD_KILL].each { |cmd|
157
+ path = $rubyrun_working_dir + cmd + '_' + Process.pid.to_s
158
+ next unless File.exist?(path)
159
+ File.directory?(path) ? Dir.delete(path) : File.delete(path)
160
+ }
161
+ end
162
+
163
+ # If exists, indicate to the monitor thread that a thread
164
+ # status report is requested
165
+ def thread_status?
166
+ File.exists?($rubyrun_working_dir + RUBYRUN_CMD_STATUS)
167
+ end
168
+
169
+ # If exists, indicate to the monitor thread that a soft kill
170
+ # (kill all threads except the main thread) command is sent
171
+ def soft_kill?
172
+ File.exists?($rubyrun_working_dir + RUBYRUN_CMD_SOFT_KILL + '_' + Process.pid.to_s)
173
+ end
174
+
175
+ # If exists, indicate to the monitor thread that a hard kill
176
+ # (kill all threads including the main thread) command is sent
177
+ def hard_kill?
178
+ File.exists?($rubyrun_working_dir + RUBYRUN_CMD_HARD_KILL + '_' + Process.pid.to_s)
179
+ end
180
+
181
+ # If exists, indicate to the montior thread that a object map is requested
182
+ def object_map?
183
+ File.exists?($rubyrun_working_dir + RUBYRUN_CMD_OBJECT_MAP)
184
+ end
185
+
186
+ # If exists, indicate to the monitor thread to exit
187
+ def exit_monitor?
188
+ File.exists?($rubyrun_working_dir + RUBYRUN_CMD_EXIT)
189
+ end
190
+
191
+ # Log if native library can't be loaded or not found
192
+ def unsupport_function
193
+ $rubyrun_logger.info "Native library not available. Function not supported."
194
+ end
195
+
196
+ end
@@ -0,0 +1,35 @@
1
+ #---------------------------------------------------------------#
2
+ # #
3
+ # (C) Copyright Rubysophic Inc. 2007-2008 #
4
+ # All rights reserved. #
5
+ # #
6
+ # Use, duplication or disclosure of the code is not permitted #
7
+ # unless licensed. #
8
+ # Dynamic Application Discovery #
9
+ # #
10
+ # Last Updated: 7/09/08 #
11
+ #---------------------------------------------------------------#
12
+ # #
13
+ # Dynamic Application Discovery lists out the name of a method #
14
+ # as it is being added to the ruby process. #
15
+ # #
16
+ #---------------------------------------------------------------#
17
+ module RubyRunDad__
18
+
19
+ # perform dynamic application discovery if requested by printing
20
+ # out the class and method name of the method being added
21
+ def get_dad(type, klass, id)
22
+ print_method_added(type, klass, id) if $rubyrun_dad
23
+ end
24
+
25
+ private
26
+
27
+ # print the dynamic method added message
28
+ def print_method_added(type, obj, id)
29
+ if type == 'i'
30
+ $rubyrun_logger.info "#{obj.to_s}.#{id.id2name} added as an instance method"
31
+ else
32
+ $rubyrun_logger.info "#{obj.to_s}.#{id.id2name} added as an singleton method"
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,52 @@
1
+ #---------------------------------------------------------------#
2
+ # #
3
+ # (C) Copyright Rubysophic Inc. 2007-2008 #
4
+ # All rights reserved. #
5
+ # #
6
+ # Use, duplication or disclosure of the code is not permitted #
7
+ # unless licensed. #
8
+ # #
9
+ # Last Updated: 7/09/08 #
10
+ #---------------------------------------------------------------#
11
+ # #
12
+ # Provide CONSTANTS for RubyRun modules #
13
+ # #
14
+ #---------------------------------------------------------------#
15
+ module RubyRunGlobals
16
+
17
+ RUBYRUN_PREFIX = 'rubyrunX'
18
+ RUBYRUN_PREFIX_LENGTH = RUBYRUN_PREFIX.length
19
+ RUBYRUN_HIGHLIGHT_THRESHOLD = 1
20
+ RUBYRUN_FIREWALL_HASH = {"Gem" => [], "gem" => [], "FileUtils::Verbose" => [], "FileUtils" => [],
21
+ "Module" => [], "Object" => [], "Time" => [], "Logger" => [], "Thread" => [],
22
+ "*" => ['method_added', 'initialize', 'singleton_method_added', 'send', 'caller']}
23
+ RUBYRUN_WORKING_DIR_NAME = 'rubyrun'
24
+ RUBYRUN_ETC_DIR = 'etc'
25
+ RUBYRUN_LOG = '/log'
26
+ RUBYRUN_REPORT = '/report'
27
+ RUBYRUN_SIGNATURE = '/signatures'
28
+ RUBYRUN_INCLUDE_HASH_FILE = '/include_hash_file'
29
+ RUBYRUN_EXCLUDE_HASH_FILE = '/exclude_hash_file'
30
+ RUBYRUN_DIR_HASH_FILE = '/dir_hash_file'
31
+ RUBYRUN_CMD_SOFT_KILL = '/cmd_soft_kill'
32
+ RUBYRUN_CMD_HARD_KILL = '/cmd_hard_kill'
33
+ RUBYRUN_CMD_STATUS = '/cmd_status'
34
+ RUBYRUN_CMD_EXIT = '/cmd_exit'
35
+ RUBYRUN_CMD_OBJECT_MAP = '/cmd_object_map'
36
+ RUBYRUN_MONITOR_TIMER = 10
37
+ RUBYRUN_OUTPUT_PERF_SUMMARY = 'perf_summary'
38
+ RUBYRUN_OUTPUT_TXN_LOG = 'txn_log'
39
+ RUBYRUN_KILL_3_STRING = 'RUBYRUN kill -3'
40
+ RUBYRUN_OPTS_FILE = '/rubyrun_opts.yml'
41
+ RUBYRUN_PROP_DEFAULTS = {"APP_PATHS"=>[], "EXCLUDE_HASH"=>{}, "INCLUDE_HASH"=>{},
42
+ "DEBUG_ARGS"=>false, "DEBUG_OBJ"=>false, "DAD"=>false,
43
+ "REPORT_TIMER"=>60, "REPORT_SHIFT_AGE"=>60,
44
+ "OUTPUT" => ["#{RUBYRUN_OUTPUT_PERF_SUMMARY}","#{RUBYRUN_OUTPUT_TXN_LOG}","#{RUBYRUN_OUTPUT_PERF_SUMMARY}"],
45
+ "RSS_PATH" => nil, "TRACE_HASH"=>{}, "DB_ADAPTER_HASH"=>{}}
46
+ RUBYRUN_ACTIVERECORD = 'ActiveRecord::Base'
47
+ RUBYRUN_VIEW_HASH = {'ActionView::Base' => ['pick_template_extension','render_file']}
48
+ RUBYRUN_THREAD_END_HASH = {'WEBrick::HTTPServer' => ['run'], 'Mongrel::HttpServer' => ['process_client']}
49
+ RUBYRUN_OUTER_DISPATCH_HASH = {'Mongrel::Rails::RailsHandler' => ['process'], 'DispatchServlet' => ['service']}
50
+ RUBYRUN_INNER_DISPATCH_HASH = { 'Dispatcher' => ['dispatch'], 'ActionController::Dispatcher' => ['dispatch']}
51
+
52
+ end
@@ -0,0 +1,136 @@
1
+ #-----------------------------------------------------------------#
2
+ # #
3
+ # (C) Copyright Rubysophic Inc. 2007-2008 #
4
+ # All rights reserved. #
5
+ # #
6
+ # Use, duplication or disclosure of the code is not permitted #
7
+ # unless licensed. #
8
+ # #
9
+ # Last Updated: 7/08/08 #
10
+ #-----------------------------------------------------------------#
11
+ # #
12
+ # RubyRunHTML__ defines HTML templates and assigns them to #
13
+ # various constants to be used by other reporter modules. #
14
+ # The templates include thread status, method trace and RSS #
15
+ # content. #
16
+ # #
17
+ #-----------------------------------------------------------------#
18
+ module RubyRunHTML__
19
+ OBJ_MAP_HTML = "<table cellspacing='2' width='55%'>
20
+ <tr align='middle' bgcolor='#43bfc7'>
21
+ <th colspan='2'><font face='Helvetica' size='2' color='white'>Top 20 Ruby classes with the largest number of objects (%START_TIMESTAMP%)</font></th></tr>
22
+ <tr align='middle' bgcolor='#43bfc7'>
23
+ <th><font face='Helvetica' size='2' color='white'>Class name</font></th>
24
+ <th><font face='Helvetica' size='2' color='white'>Number of objects</font></th>
25
+ %OBJ_MAP_ROW%
26
+ </table><br></br>"
27
+ OBJ_MAP_ODD_ROW = "<tr align='middle'>
28
+ <td align='left' bgcolor='#afdcec'><font face='Tahoma' size='2' color='black'>%s</font></td>
29
+ <td align='left' bgcolor='#afdcec'><font face='Tahoma' size='2' color='black'>%s</font></td>"
30
+ OBJ_MAP_EVEN_ROW = "<tr align='middle'>
31
+ <td align='left'><font face='Tahoma' size='2' color='black'>%s</font></td>
32
+ <td align='left'><font face='Tahoma' size='2' color='black'>%s</font></td>"
33
+ THREAD_STATUS_HTML = "<table cellspacing='2' width='100%'>
34
+ <tr align='middle' bgcolor='#43bfc7'>
35
+ <th colspan='3'><font face='Helvetica' size='2' color='white'>RubyRun Thread Status Starts (%START_TIMESTAMP%)</font></th>
36
+ <tr align='middle' bgcolor='#43bfc7'>
37
+ <th><font face='Helvetica' size='2' color='white'>Thread ID</font></th>
38
+ <th><font face='Helvetica' size='2' color='white'>Status</font></th>
39
+ <th><font face='Helvetica' size='2' color='white'>Top of the stack</font></th>
40
+ %THREAD_STATUS_ROW%
41
+ </table><br></br>"
42
+ THREAD_STATUS_ODD_ROW = "<tr align='middle'>
43
+ <td bgcolor='#afdcec'><font face='Tahoma' size='2' color='black'>%s</font></td>
44
+ <td bgcolor='#afdcec'><font face='Tahoma' size='2' color='black'>%s</font></td>
45
+ <td align='left' bgcolor='#afdcec'><font face='Tahoma' size='2' color='black'>%s</font></td>"
46
+ THREAD_STATUS_EVEN_ROW = "<tr align='middle'>
47
+ <td><font face='Tahoma' size='2' color='black'>%s</font></td>
48
+ <td><font face='Tahoma' size='2' color='black'>%s</font></td>
49
+ <td align='left'><font face='Tahoma' size='2' color='black'>%s</font></td></tr>"
50
+
51
+ METHOD_TRACE_HEADER = "<table cellspacing=2 width=100%>
52
+ <tr align=center bgcolor=#43BFC7>
53
+ <th><font face=Helvetica size=2 color=white>Time</font></th>
54
+ <th><font face=Helvetica size=2 color=white>Thread ID</font></th>
55
+ <th><font face=Helvetica size=2 color=white>Method Entry/Exit</font></th>
56
+ <th><font face=Helvetica size=2 color=white>Time Taken</font></th>
57
+ <th><font face=Helvetica size=2 color=white>Class</font></th>
58
+ <th><font face=Helvetica size=2 color=white>Method</font></th>
59
+ <th><font face=Helvetica size=2 color=white>Parameter Value(s)</font></th>
60
+ <th><font face=Helvetica size=2 color=white>Caller Object Class</font></th>
61
+ <th><font face=Helvetica size=2 color=white>Caller Method</font></th></tr>"
62
+ METHOD_TRACE_ODD_ROW = "<tr align=center>
63
+ <td bgcolor=#AFDCEC><font face='Tahoma' size=2 color=black>%s</font></td>
64
+ <td bgcolor=#AFDCEC><font face='Tahoma' size=2 color=black>%s</font></td>
65
+ <td bgcolor=#AFDCEC><font face='Tahoma' size=2 color=black>%s</font></td>
66
+ <td bgcolor=%s><font face='Tahoma' size=2 color=black>%s</font></td>
67
+ <td align=left bgcolor=#AFDCEC><font face='Tahoma' size=2 color=black>%s</font></td>
68
+ <td align=left bgcolor=#AFDCEC><font face='Tahoma' size=2 color=black>%s</font></td>
69
+ <td align=left bgcolor=#AFDCEC><font face='Tahoma' size=2 color=black>%s</font></td>
70
+ <td align=left bgcolor=#AFDCEC><font face='Tahoma' size=2 color=black>%s</font></td>
71
+ <td align=left bgcolor=#AFDCEC><font face='Tahoma' size=2 color=black>%s</font></td></tr>"
72
+ METHOD_TRACE_EVEN_ROW = "<tr align=center>
73
+ <td><font face='Tahoma' size=2 color=black>%s</font></td>
74
+ <td><font face='Tahoma' size=2 color=black>%s</font></td>
75
+ <td><font face='Tahoma' size=2 color=black>%s</font></td>
76
+ <td bgcolor=%s><font face='Tahoma' size=2 color=black>%s</font></td>
77
+ <td align=left><font face='Tahoma' size=2 color=black>%s</font></td>
78
+ <td align=left><font face='Tahoma' size=2 color=black>%s</font></td>
79
+ <td align=left><font face='Tahoma' size=2 color=black>%s</font></td>
80
+ <td align=left><font face='Tahoma' size=2 color=black>%s</font></td>
81
+ <td align=left><font face='Tahoma' size=2 color=black>%s</font></td></tr>"
82
+
83
+ THROUGHPUT_HTML = "<p align=center><font size='3' face='Verdana'>Performance summary of %APPS_NAME% as of %TIMESTAMP%</font></p>
84
+ <table id=tblgraph align=center width=80 cellpadding=2 cellspacing=0 border=0>
85
+ <tr><td bgcolor=WHITE align=center valign=middle width=22 style='writing-mode:tb-rl'><font face=arial size='-1'>Average throughput per min</font></td>%THROUGHPUT_BAR_TABLE%</tr>
86
+ <tr bgcolor=#505050>
87
+ <td align=center bordor=1 bgcolor=#FFFFFF>&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