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
data/html/rdoc-style.css
ADDED
@@ -0,0 +1,208 @@
|
|
1
|
+
|
2
|
+
body {
|
3
|
+
font-family: Verdana,Arial,Helvetica,sans-serif;
|
4
|
+
font-size: 90%;
|
5
|
+
margin: 0;
|
6
|
+
margin-left: 40px;
|
7
|
+
padding: 0;
|
8
|
+
background: white;
|
9
|
+
}
|
10
|
+
|
11
|
+
h1,h2,h3,h4 { margin: 0; color: #efefef; background: transparent; }
|
12
|
+
h1 { font-size: 150%; }
|
13
|
+
h2,h3,h4 { margin-top: 1em; }
|
14
|
+
|
15
|
+
a { background: #eef; color: #039; text-decoration: none; }
|
16
|
+
a:hover { background: #039; color: #eef; }
|
17
|
+
|
18
|
+
/* Override the base stylesheet's Anchor inside a table cell */
|
19
|
+
td > a {
|
20
|
+
background: transparent;
|
21
|
+
color: #039;
|
22
|
+
text-decoration: none;
|
23
|
+
}
|
24
|
+
|
25
|
+
/* and inside a section title */
|
26
|
+
.section-title > a {
|
27
|
+
background: transparent;
|
28
|
+
color: #eee;
|
29
|
+
text-decoration: none;
|
30
|
+
}
|
31
|
+
|
32
|
+
/* === Structural elements =================================== */
|
33
|
+
|
34
|
+
div#index {
|
35
|
+
margin: 0;
|
36
|
+
margin-left: -40px;
|
37
|
+
padding: 0;
|
38
|
+
font-size: 90%;
|
39
|
+
}
|
40
|
+
|
41
|
+
|
42
|
+
div#index a {
|
43
|
+
margin-left: 0.7em;
|
44
|
+
}
|
45
|
+
|
46
|
+
div#index .section-bar {
|
47
|
+
margin-left: 0px;
|
48
|
+
padding-left: 0.7em;
|
49
|
+
background: #ccc;
|
50
|
+
font-size: small;
|
51
|
+
}
|
52
|
+
|
53
|
+
|
54
|
+
div#classHeader, div#fileHeader {
|
55
|
+
width: auto;
|
56
|
+
color: white;
|
57
|
+
padding: 0.5em 1.5em 0.5em 1.5em;
|
58
|
+
margin: 0;
|
59
|
+
margin-left: -40px;
|
60
|
+
border-bottom: 3px solid #006;
|
61
|
+
}
|
62
|
+
|
63
|
+
div#classHeader a, div#fileHeader a {
|
64
|
+
background: inherit;
|
65
|
+
color: white;
|
66
|
+
}
|
67
|
+
|
68
|
+
div#classHeader td, div#fileHeader td {
|
69
|
+
background: inherit;
|
70
|
+
color: white;
|
71
|
+
}
|
72
|
+
|
73
|
+
|
74
|
+
div#fileHeader {
|
75
|
+
background: #057;
|
76
|
+
}
|
77
|
+
|
78
|
+
div#classHeader {
|
79
|
+
background: #048;
|
80
|
+
}
|
81
|
+
|
82
|
+
|
83
|
+
.class-name-in-header {
|
84
|
+
font-size: 180%;
|
85
|
+
font-weight: bold;
|
86
|
+
}
|
87
|
+
|
88
|
+
|
89
|
+
div#bodyContent {
|
90
|
+
padding: 0 1.5em 0 1.5em;
|
91
|
+
}
|
92
|
+
|
93
|
+
div#description {
|
94
|
+
padding: 0.5em 1.5em;
|
95
|
+
background: #efefef;
|
96
|
+
border: 1px dotted #999;
|
97
|
+
}
|
98
|
+
|
99
|
+
div#description h1,h2,h3,h4,h5,h6 {
|
100
|
+
color: #125;;
|
101
|
+
background: transparent;
|
102
|
+
}
|
103
|
+
|
104
|
+
div#validator-badges {
|
105
|
+
text-align: center;
|
106
|
+
}
|
107
|
+
div#validator-badges img { border: 0; }
|
108
|
+
|
109
|
+
div#copyright {
|
110
|
+
color: #333;
|
111
|
+
background: #efefef;
|
112
|
+
font: 0.75em sans-serif;
|
113
|
+
margin-top: 5em;
|
114
|
+
margin-bottom: 0;
|
115
|
+
padding: 0.5em 2em;
|
116
|
+
}
|
117
|
+
|
118
|
+
|
119
|
+
/* === Classes =================================== */
|
120
|
+
|
121
|
+
table.header-table {
|
122
|
+
color: white;
|
123
|
+
font-size: small;
|
124
|
+
}
|
125
|
+
|
126
|
+
.type-note {
|
127
|
+
font-size: small;
|
128
|
+
color: #DEDEDE;
|
129
|
+
}
|
130
|
+
|
131
|
+
.xxsection-bar {
|
132
|
+
background: #eee;
|
133
|
+
color: #333;
|
134
|
+
padding: 3px;
|
135
|
+
}
|
136
|
+
|
137
|
+
.section-bar {
|
138
|
+
color: #333;
|
139
|
+
border-bottom: 1px solid #999;
|
140
|
+
margin-left: -20px;
|
141
|
+
}
|
142
|
+
|
143
|
+
|
144
|
+
.section-title {
|
145
|
+
background: #79a;
|
146
|
+
color: #eee;
|
147
|
+
padding: 3px;
|
148
|
+
margin-top: 2em;
|
149
|
+
margin-left: -30px;
|
150
|
+
border: 1px solid #999;
|
151
|
+
}
|
152
|
+
|
153
|
+
.top-aligned-row { vertical-align: top }
|
154
|
+
.bottom-aligned-row { vertical-align: bottom }
|
155
|
+
|
156
|
+
/* --- Context section classes ----------------------- */
|
157
|
+
|
158
|
+
.context-row { }
|
159
|
+
.context-item-name { font-family: monospace; font-weight: bold; color: black; }
|
160
|
+
.context-item-value { font-size: small; color: #448; }
|
161
|
+
.context-item-desc { color: #333; padding-left: 2em; }
|
162
|
+
|
163
|
+
/* --- Method classes -------------------------- */
|
164
|
+
.method-detail {
|
165
|
+
background: #efefef;
|
166
|
+
padding: 0;
|
167
|
+
margin-top: 0.5em;
|
168
|
+
margin-bottom: 1em;
|
169
|
+
border: 1px dotted #ccc;
|
170
|
+
}
|
171
|
+
.method-heading {
|
172
|
+
color: black;
|
173
|
+
background: #ccc;
|
174
|
+
border-bottom: 1px solid #666;
|
175
|
+
padding: 0.2em 0.5em 0 0.5em;
|
176
|
+
}
|
177
|
+
.method-signature { color: black; background: inherit; }
|
178
|
+
.method-name { font-weight: bold; }
|
179
|
+
.method-args { font-style: italic; }
|
180
|
+
.method-description { padding: 0 0.5em 0 0.5em; }
|
181
|
+
|
182
|
+
/* --- Source code sections -------------------- */
|
183
|
+
|
184
|
+
a.source-toggle { font-size: 90%; }
|
185
|
+
div.method-source-code {
|
186
|
+
background: #262626;
|
187
|
+
color: #ffdead;
|
188
|
+
margin: 1em;
|
189
|
+
padding: 0.5em;
|
190
|
+
border: 1px dashed #999;
|
191
|
+
overflow: hidden;
|
192
|
+
}
|
193
|
+
|
194
|
+
div.method-source-code pre { color: #ffdead; overflow: hidden; }
|
195
|
+
|
196
|
+
/* --- Ruby keyword styles --------------------- */
|
197
|
+
|
198
|
+
.standalone-code { background: #221111; color: #ffdead; overflow: hidden; }
|
199
|
+
|
200
|
+
.ruby-constant { color: #7fffd4; background: transparent; }
|
201
|
+
.ruby-keyword { color: #00ffff; background: transparent; }
|
202
|
+
.ruby-ivar { color: #eedd82; background: transparent; }
|
203
|
+
.ruby-operator { color: #00ffee; background: transparent; }
|
204
|
+
.ruby-identifier { color: #ffdead; background: transparent; }
|
205
|
+
.ruby-node { color: #ffa07a; background: transparent; }
|
206
|
+
.ruby-comment { color: #b22222; font-weight: bold; background: transparent; }
|
207
|
+
.ruby-regexp { color: #ffa07a; background: transparent; }
|
208
|
+
.ruby-value { color: #7fffd4; background: transparent; }
|
@@ -0,0 +1,78 @@
|
|
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
|
+
# RubyRun bootstrap code. #
|
13
|
+
# #
|
14
|
+
# To invoke RubyRun for Rails or a Ruby script, use command #
|
15
|
+
# line option -r. #
|
16
|
+
# #
|
17
|
+
# ruby -rrubyrun script/server <webrick> #
|
18
|
+
# #
|
19
|
+
# To remove RubyRun, simply remove the -r option. #
|
20
|
+
# #
|
21
|
+
# Generally no other code change is needed to run RubyRun. #
|
22
|
+
# #
|
23
|
+
#---------------------------------------------------------------#
|
24
|
+
|
25
|
+
# BEGIN section of the code is always executed first.
|
26
|
+
# 1. Intiialize globals, requires and includes
|
27
|
+
# 2. Intitialize RubyRun runtime environment
|
28
|
+
# Note. For $rubyrun_current_buffer, 1 - primary, 2 - secondary
|
29
|
+
BEGIN {
|
30
|
+
require 'rubyrun_globals'
|
31
|
+
require 'rubyrun_instrumentor__'
|
32
|
+
require 'rubyrun_monitor__'
|
33
|
+
require 'rubyrun_initializer__'
|
34
|
+
include RubyRunGlobals
|
35
|
+
include RubyRunInitializer__
|
36
|
+
include RubyRunInstrumentor__
|
37
|
+
include RubyRunMonitor__
|
38
|
+
$rubyrun_include_hash = {}
|
39
|
+
$rubyrun_exclude_hash = {}
|
40
|
+
$rubyrun_thread_stack = {}
|
41
|
+
$rubyrun_metrics_hash = {}
|
42
|
+
$rubyrun_thread_local = {}
|
43
|
+
$rubyrun_file_date_hash = {}
|
44
|
+
$rubyrun_prime_buffer = []
|
45
|
+
$rubyrun_alt_buffer = []
|
46
|
+
$rubyrun_controller_classes = []
|
47
|
+
$rubyrun_current_buffer = 1
|
48
|
+
$rubyrun_lock = Monitor.new
|
49
|
+
init_rubyrun
|
50
|
+
}
|
51
|
+
|
52
|
+
# RubyRun uses 2 traps to get control from the interpreter
|
53
|
+
# to decide if a method should be instrumented or passed
|
54
|
+
#
|
55
|
+
# 1. When an instance method is added when a module/class is
|
56
|
+
# loaded, or dynamically created
|
57
|
+
# 2. When a module/static/singleton method is added when a
|
58
|
+
# module/class is loaded, or dynamically created
|
59
|
+
class Module
|
60
|
+
# module/class instance method trap
|
61
|
+
def method_added(id, *args)
|
62
|
+
RubyRunInstrumentor__.instrument_it?('i', self, id)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class Object
|
67
|
+
# class object/object singleton method trap
|
68
|
+
def singleton_method_added(id, *args)
|
69
|
+
RubyRunInstrumentor__.instrument_it?('s', self, id)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# 1. Instrument Thread.new method to provide a begin/rescue clause
|
74
|
+
# to catch failure for providing a stack trace
|
75
|
+
#
|
76
|
+
# 2. Start the monitor timer thread
|
77
|
+
instrument_thread_new
|
78
|
+
start_thread_monitor
|
@@ -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 = ENV[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?(ENV[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?(ENV[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?(ENV[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?(ENV[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?(ENV[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,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
|