XRay 1.0.1 → 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README +41 -12
- data/Rakefile +63 -0
- data/lib/xray/thread_dump_signal_handler.rb +31 -0
- data/patches_for_mri/caller_for_all_threads_patch_for_MRI_1.8.6.diff +229 -0
- data/{patch-for-dtrace-instrumentation-of-matz-1.8.6-p114.diff → patches_for_mri/patch-for-dtrace-instrumentation-of-matz-1.8.6-p114.diff} +13 -2
- data/{patch-for-joyent-mri-1.8.6-on-leopard.diff → patches_for_mri/patch-for-joyent-mri-1.8.6-on-mac-os-x-leopard.diff} +0 -0
- metadata +7 -5
- data/lib/xray/rails_stack_signal_handler.rb +0 -15
data/README
CHANGED
@@ -1,19 +1,44 @@
|
|
1
|
+
= XRay
|
2
|
+
|
3
|
+
* http://rubyforge.org/projects/xray
|
4
|
+
|
5
|
+
== Description
|
6
|
+
|
1
7
|
XRay provides a lightweight yet powerful toolbox for troubleshooting Ruby
|
2
|
-
applications when things stop making sense.
|
8
|
+
applications when things stop making sense. XRay includes GDB and DTrace
|
9
|
+
tooling as well as a Thread Dump utility that can dump the stack trace
|
10
|
+
of all the thread in your Ruby VM when you send a +QUIT+ signal.
|
11
|
+
|
12
|
+
== GDB
|
13
|
+
|
14
|
+
Copy the +gdb_macros+ file provided in the gem as your ~/.gdbinit file.
|
15
|
+
You will find more details on how to use them, in my
|
16
|
+
{Troubleshooting Ruby Shortcut}[http://ph7spot.com/publications/troubleshooting_ruby_processes]
|
3
17
|
|
4
|
-
|
18
|
+
== Thread Dump
|
5
19
|
|
20
|
+
After patching your Ruby VM with {caller_for_all_threads_patch_for_MRI_1.8.6.diff}[http://xray.rubyforge.org/svn/patches_for_mri/caller_for_all_threads_patch_for_MRI_1.8.6.diff]
|
21
|
+
as explained in {this document}[http://ph7spot.com/caller_for_all_threads], you can install a signal
|
22
|
+
handler in charge of dumping the stack trace for all the threads
|
23
|
+
in your Ruby VM with:
|
6
24
|
|
7
|
-
|
25
|
+
require "xray"
|
26
|
+
require "xray/thread_dump_signal_handler"
|
8
27
|
|
9
|
-
|
28
|
+
You can then trigger a thread dump at any time with
|
10
29
|
|
11
|
-
|
30
|
+
kill -QUIT <pid of your ruby process>
|
12
31
|
|
13
|
-
|
32
|
+
== DTrace
|
14
33
|
|
15
|
-
|
16
|
-
|
34
|
+
=== Fire DTrace Application Probes
|
35
|
+
|
36
|
+
See XRay::DTrace::Tracer
|
37
|
+
|
38
|
+
=== Out-of-the-box Rails DTrace Instrumentation ***
|
39
|
+
|
40
|
+
You are one require away from triggering automatically DTrace events for
|
41
|
+
Rails requests, database access and template rendering. As simple as
|
17
42
|
|
18
43
|
# environment.rb
|
19
44
|
Rails::Initializer.run do |config|
|
@@ -25,10 +50,14 @@ applications when things stop making sense. Includes GDB and DTrace tooling.
|
|
25
50
|
end
|
26
51
|
end
|
27
52
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
53
|
+
See
|
54
|
+
* lib/xray/dtrace/railsenable_tracing.rb
|
55
|
+
* lib/xray/dtrace/action_controller_tracing_extension.rb
|
56
|
+
* lib/xray/dtrace/active_record_tracing_extension.rb
|
57
|
+
|
32
58
|
|
59
|
+
== Author
|
33
60
|
|
61
|
+
Philippe Hanrigou,
|
62
|
+
http://ph7spot.com
|
34
63
|
|
data/Rakefile
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
require 'rake/gempackagetask'
|
5
|
+
require 'rake/clean'
|
6
|
+
require 'rubygems'
|
7
|
+
|
8
|
+
CLEAN.include '**/*.o'
|
9
|
+
CLEAN.include '**/*.so'
|
10
|
+
CLEAN.include '**/*.bundle'
|
11
|
+
CLOBBER.include '**/*.log'
|
12
|
+
CLOBBER.include '**/Makefile'
|
13
|
+
CLOBBER.include '**/extconf.h'
|
14
|
+
|
15
|
+
desc 'Default: run unit tests.'
|
16
|
+
task :default => :test
|
17
|
+
|
18
|
+
|
19
|
+
desc 'Test XRay.'
|
20
|
+
Rake::TestTask.new(:test) do |t|
|
21
|
+
t.libs << 'lib'
|
22
|
+
t.pattern = 'test/**/*_test.rb'
|
23
|
+
t.verbose = true
|
24
|
+
end
|
25
|
+
|
26
|
+
desc 'Generate documentation for XRay.'
|
27
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
28
|
+
rdoc.rdoc_dir = 'rdoc'
|
29
|
+
rdoc.title = 'XRay'
|
30
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
31
|
+
rdoc.rdoc_files.include('README')
|
32
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
33
|
+
end
|
34
|
+
|
35
|
+
specification = Gem::Specification.new do |s|
|
36
|
+
s.name = "XRay"
|
37
|
+
s.summary = "Dump backtrace for all threads."
|
38
|
+
s.version = "1.0.3"
|
39
|
+
s.author = "Philippe Hanrigou"
|
40
|
+
s.email = 'xray-developer@rubyforge.org'
|
41
|
+
s.homepage = "http://xray.rubyforge.com"
|
42
|
+
s.rubyforge_project = 'xray'
|
43
|
+
s.platform = Gem::Platform::RUBY
|
44
|
+
s.files = FileList['lib/**/*.rb'] + FileList['test/**/*.rb'] +
|
45
|
+
FileList['**/*.d'] + FileList['**/*.diff'] +
|
46
|
+
[ 'gdb_macros', 'Rakefile' ]
|
47
|
+
s.require_path = "lib"
|
48
|
+
s.extensions = []
|
49
|
+
s.rdoc_options << '--title' << 'XRay' << '--main' << 'README' << '--line-numbers'
|
50
|
+
s.has_rdoc = true
|
51
|
+
s.extra_rdoc_files = ['README']
|
52
|
+
s.test_file = "test/all_tests.rb"
|
53
|
+
end
|
54
|
+
|
55
|
+
Rake::GemPackageTask.new(specification) do |package|
|
56
|
+
package.need_zip = false
|
57
|
+
package.need_tar = false
|
58
|
+
end
|
59
|
+
|
60
|
+
desc "Publish RDoc on Rubyforge website"
|
61
|
+
task :publish_rdoc => :rdoc do
|
62
|
+
sh "scp -i ~/.ssh/id_dsa -r rdoc/* #{ENV['USER']}@rubyforge.org:/var/www/gforge-projects/xray"
|
63
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#
|
2
|
+
# Install a signal handler to dump backtraces for all threads
|
3
|
+
#
|
4
|
+
# Trigger it with: kill -QUIT <pid>
|
5
|
+
#
|
6
|
+
trap "QUIT" do
|
7
|
+
if Kernel.respond_to? :caller_for_all_threads
|
8
|
+
STDERR.puts "\n=============== XRay - Thread Dump ==============="
|
9
|
+
caller_for_all_threads.each_pair do |thread, stack|
|
10
|
+
thread_description = thread.inspect
|
11
|
+
thread_description << " [main]" if thread == Thread.main
|
12
|
+
thread_description << " [current]" if thread == Thread.current
|
13
|
+
thread_description << " alive=#{thread.alive?}"
|
14
|
+
thread_description << " priority=#{thread.priority}"
|
15
|
+
thread_separator = "-" * 78
|
16
|
+
|
17
|
+
full_description = "\n#{thread_separator}\n"
|
18
|
+
full_description << thread_description
|
19
|
+
full_description << "\n#{thread_separator}\n"
|
20
|
+
full_description << " #{stack.join("\n \\_ ")}\n"
|
21
|
+
|
22
|
+
# Single puts to avoid interleaved output
|
23
|
+
STDERR.puts full_description
|
24
|
+
end
|
25
|
+
else
|
26
|
+
STDERR.puts "=============== XRay - Current Thread Backtrace ==============="
|
27
|
+
STDERR.puts "Current thread : #{Thread.inspect}"
|
28
|
+
STDERR.puts caller.join("\n \\_ ")
|
29
|
+
end
|
30
|
+
STDERR.puts "\n=============== XRay - Done ===============\n"
|
31
|
+
end
|
@@ -0,0 +1,229 @@
|
|
1
|
+
Index: test/callerforallthreads/test_caller_for_each_thread.rb
|
2
|
+
===================================================================
|
3
|
+
--- test/callerforallthreads/test_caller_for_each_thread.rb (revision 0)
|
4
|
+
+++ test/callerforallthreads/test_caller_for_each_thread.rb (revision 0)
|
5
|
+
@@ -0,0 +1,95 @@
|
6
|
+
+# -*- ruby-indent-level: 4 -*-
|
7
|
+
+require 'thread'
|
8
|
+
+require 'test/unit'
|
9
|
+
+
|
10
|
+
+class AClassWithNestedmethods
|
11
|
+
+
|
12
|
+
+ def an_ultra_nested_method(skip)
|
13
|
+
+ caller_for_all_threads skip
|
14
|
+
+ end
|
15
|
+
+
|
16
|
+
+ def a_nested_method(skip)
|
17
|
+
+ an_ultra_nested_method skip
|
18
|
+
+ end
|
19
|
+
+
|
20
|
+
+ def a_method(skip=0)
|
21
|
+
+ a_nested_method skip
|
22
|
+
+ end
|
23
|
+
+
|
24
|
+
+end
|
25
|
+
+
|
26
|
+
+class CallerForEachThreadTest < Test::Unit::TestCase
|
27
|
+
+
|
28
|
+
+ def testCollectMeaningfulBacktraceForASingleThread
|
29
|
+
+ backtraces = AClassWithNestedmethods.new.a_method
|
30
|
+
+ backtrace = backtraces[Thread.current]
|
31
|
+
+ assert_not_nil backtrace
|
32
|
+
+ assert_equal __FILE__ + ":8:in `an_ultra_nested_method'", backtrace[0]
|
33
|
+
+ assert_equal __FILE__ + ":12:in `a_nested_method'", backtrace[1]
|
34
|
+
+ assert_equal __FILE__ + ":16:in `a_method'", backtrace[2]
|
35
|
+
+ assert_equal __FILE__ + ":24:in `testCollectMeaningfulBacktraceForASingleThread'",
|
36
|
+
+ backtrace[3]
|
37
|
+
+ end
|
38
|
+
+
|
39
|
+
+ def testCanSkipFirstStackEntries
|
40
|
+
+ backtraces = AClassWithNestedmethods.new.a_method 2
|
41
|
+
+ backtrace = backtraces[Thread.current]
|
42
|
+
+ assert_not_nil backtrace
|
43
|
+
+ assert_equal __FILE__ + ":16:in `a_method'", backtrace[0]
|
44
|
+
+ assert_equal __FILE__ + ":35:in `testCanSkipFirstStackEntries'",
|
45
|
+
+ backtrace[1]
|
46
|
+
+ end
|
47
|
+
+
|
48
|
+
+ def testCollectMeaningfulBacktraceForMultipleThreads
|
49
|
+
+ first_thread = Thread.new do
|
50
|
+
+ loop do
|
51
|
+
+ Thread.pass
|
52
|
+
+ sleep 1
|
53
|
+
+ end
|
54
|
+
+ end
|
55
|
+
+
|
56
|
+
+ second_thread = Thread.new do
|
57
|
+
+ loop do
|
58
|
+
+ Thread.pass
|
59
|
+
+ sleep 1
|
60
|
+
+ end
|
61
|
+
+ end
|
62
|
+
+
|
63
|
+
+ backtraces = AClassWithNestedmethods.new.a_method
|
64
|
+
+
|
65
|
+
+ backtrace = backtraces[Thread.current]
|
66
|
+
+ assert_not_nil backtrace
|
67
|
+
+ assert_match __FILE__ + ":8:in `an_ultra_nested_method'", backtrace[0]
|
68
|
+
+ assert_match __FILE__ + ":12:in `a_nested_method'", backtrace[1]
|
69
|
+
+ assert_equal __FILE__ + ":16:in `a_method'", backtrace[2]
|
70
|
+
+ assert_equal __FILE__ + ":58:in `testCollectMeaningfulBacktraceForMultipleThreads'",
|
71
|
+
+ backtrace[3]
|
72
|
+
+
|
73
|
+
+ backtrace = backtraces[first_thread]
|
74
|
+
+ assert_not_nil backtrace
|
75
|
+
+ assert_equal __FILE__ + ":47:in `testCollectMeaningfulBacktraceForMultipleThreads'",
|
76
|
+
+ backtrace[0]
|
77
|
+
+ assert_equal __FILE__ + ":45:in `loop'",
|
78
|
+
+ backtrace[1]
|
79
|
+
+ assert_equal __FILE__ + ":45:in `testCollectMeaningfulBacktraceForMultipleThreads'",
|
80
|
+
+ backtrace[2]
|
81
|
+
+ assert_equal __FILE__ + ":44:in `initialize'",backtrace[3]
|
82
|
+
+ assert_equal __FILE__ + ":44:in `new'", backtrace[4]
|
83
|
+
+ assert_equal __FILE__ + ":44:in `testCollectMeaningfulBacktraceForMultipleThreads'",
|
84
|
+
+ backtrace[5]
|
85
|
+
+
|
86
|
+
+ backtrace = backtraces[second_thread]
|
87
|
+
+ assert_not_nil backtrace
|
88
|
+
+ assert_equal __FILE__ + ":53:in `testCollectMeaningfulBacktraceForMultipleThreads'",
|
89
|
+
+ backtrace[0]
|
90
|
+
+ assert_equal __FILE__ + ":52:in `loop'", backtrace[1]
|
91
|
+
+ assert_equal __FILE__ + ":52:in `testCollectMeaningfulBacktraceForMultipleThreads'",
|
92
|
+
+ backtrace[2]
|
93
|
+
+ assert_equal __FILE__ + ":51:in `initialize'",backtrace[3]
|
94
|
+
+ assert_equal __FILE__ + ":51:in `new'", backtrace[4]
|
95
|
+
+ assert_equal __FILE__ + ":51:in `testCollectMeaningfulBacktraceForMultipleThreads'",
|
96
|
+
+ backtrace[5]
|
97
|
+
+ end
|
98
|
+
+
|
99
|
+
+end
|
100
|
+
+
|
101
|
+
Index: eval.c
|
102
|
+
===================================================================
|
103
|
+
--- eval.c (revision 16289)
|
104
|
+
+++ eval.c (working copy)
|
105
|
+
@@ -7969,6 +7969,17 @@
|
106
|
+
ruby_safe_level = safe;
|
107
|
+
}
|
108
|
+
|
109
|
+
+/* Hash (Thread => Backtrace) used to collect backtrace for each threads. */
|
110
|
+
+static VALUE backtrace_for_each_thread;
|
111
|
+
+
|
112
|
+
+static int backtrace_level_for_each_thread;
|
113
|
+
+
|
114
|
+
+static VALUE
|
115
|
+
+switch_thread_context_to_collect_backtrace(rb_thread_t next);
|
116
|
+
+
|
117
|
+
+static VALUE
|
118
|
+
+rb_f_caller_for_all_threads();
|
119
|
+
+
|
120
|
+
void
|
121
|
+
Init_eval()
|
122
|
+
{
|
123
|
+
@@ -8014,6 +8025,7 @@
|
124
|
+
rb_define_global_function("fail", rb_f_raise, -1);
|
125
|
+
|
126
|
+
rb_define_global_function("caller", rb_f_caller, -1);
|
127
|
+
+ rb_define_global_function("caller_for_all_threads", rb_f_caller_for_all_threads, -1);
|
128
|
+
|
129
|
+
rb_define_global_function("exit", rb_f_exit, -1);
|
130
|
+
rb_define_global_function("abort", rb_f_abort, -1);
|
131
|
+
@@ -10206,6 +10218,7 @@
|
132
|
+
#define RESTORE_RAISE 5
|
133
|
+
#define RESTORE_SIGNAL 6
|
134
|
+
#define RESTORE_EXIT 7
|
135
|
+
+#define RESTORE_BACKTRACE 8
|
136
|
+
|
137
|
+
extern VALUE *rb_gc_stack_start;
|
138
|
+
#ifdef __ia64
|
139
|
+
@@ -10313,6 +10326,15 @@
|
140
|
+
}
|
141
|
+
rb_exc_raise(th_raise_exception);
|
142
|
+
break;
|
143
|
+
+ case RESTORE_BACKTRACE:
|
144
|
+
+ rb_hash_aset(backtrace_for_each_thread, curr_thread->thread,
|
145
|
+
+ backtrace(backtrace_level_for_each_thread));
|
146
|
+
+ if (curr_thread != main_thread) {
|
147
|
+
+ switch_thread_context_to_collect_backtrace(curr_thread->next);
|
148
|
+
+ } else {
|
149
|
+
+ /* Circled back to main thread, cycle is complete. */
|
150
|
+
+ }
|
151
|
+
+ break;
|
152
|
+
case RESTORE_NORMAL:
|
153
|
+
default:
|
154
|
+
break;
|
155
|
+
@@ -13240,3 +13262,74 @@
|
156
|
+
argv[1] = val;
|
157
|
+
rb_f_throw(2, argv);
|
158
|
+
}
|
159
|
+
+
|
160
|
+
+static VALUE
|
161
|
+
+switch_thread_context_to_collect_backtrace(rb_thread_t next)
|
162
|
+
+{
|
163
|
+
+ if (THREAD_SAVE_CONTEXT(curr_thread)) {
|
164
|
+
+ return Qnil;
|
165
|
+
+ }
|
166
|
+
+ curr_thread = next;
|
167
|
+
+ rb_thread_restore_context(next, RESTORE_BACKTRACE);
|
168
|
+
+ return Qnil;
|
169
|
+
+}
|
170
|
+
+
|
171
|
+
+
|
172
|
+
+/*
|
173
|
+
+ * call-seq:
|
174
|
+
+ * caller_for_all_threads(start=1) => array
|
175
|
+
+ *
|
176
|
+
+ * Returns the current execution stack for all threads
|
177
|
+
+ * ---a hash whose keys are thread instances and values
|
178
|
+
+ * the thread caller backtrace.
|
179
|
+
+ *
|
180
|
+
+ * Backtraces are array of hashes indicating location on the
|
181
|
+
+ * stack. Hash keys include ``<em>:line</em>'' or ``<em>:file</em>''
|
182
|
+
+ * and ``<em>:method'</em>''.
|
183
|
+
+ *
|
184
|
+
+ * The optional _start_ parameter
|
185
|
+
+ * determines the number of initial stack entries to omit from the
|
186
|
+
+ * result.
|
187
|
+
+ *
|
188
|
+
+ * def a(skip)
|
189
|
+
+ * caller_for_all_threads(skip)
|
190
|
+
+ * end
|
191
|
+
+ * def b(skip)
|
192
|
+
+ * a(skip)
|
193
|
+
+ * end
|
194
|
+
+ * def c(skip)
|
195
|
+
+ * b(skip)
|
196
|
+
+ * end
|
197
|
+
+ * c(0) #=> ["prog:2:in `a'", "prog:5:in `b'", "prog:8:in `c'", "prog:10"]
|
198
|
+
+ * c(1) #=> ["prog:5:in `b'", "prog:8:in `c'", "prog:11"]
|
199
|
+
+ * c(2) #=> ["prog:8:in `c'", "prog:12"]
|
200
|
+
+ * c(3) #=> ["prog:13"]
|
201
|
+
+ */
|
202
|
+
+static VALUE
|
203
|
+
+rb_f_caller_for_all_threads(argc, argv)
|
204
|
+
+ int argc;
|
205
|
+
+ VALUE *argv;
|
206
|
+
+{
|
207
|
+
+ volatile int critical;
|
208
|
+
+ VALUE level;
|
209
|
+
+ VALUE result;
|
210
|
+
+
|
211
|
+
+ rb_scan_args(argc, argv, "01", &level);
|
212
|
+
+ backtrace_level_for_each_thread = NIL_P(level) ? 0 : NUM2INT(level);
|
213
|
+
+ if (backtrace_level_for_each_thread < 0) {
|
214
|
+
+ rb_raise(rb_eArgError, "negative level (%d)", backtrace_level_for_each_thread);
|
215
|
+
+ }
|
216
|
+
+
|
217
|
+
+ critical = rb_thread_critical;
|
218
|
+
+ rb_thread_critical = Qtrue;
|
219
|
+
+
|
220
|
+
+ backtrace_for_each_thread = rb_hash_new();
|
221
|
+
+ switch_thread_context_to_collect_backtrace(main_thread->next);
|
222
|
+
+
|
223
|
+
+ result = backtrace_for_each_thread;
|
224
|
+
+ backtrace_for_each_thread = Qnil;
|
225
|
+
+ backtrace_for_each_thread = 0;
|
226
|
+
+
|
227
|
+
+ rb_thread_critical = critical;
|
228
|
+
+ return result;
|
229
|
+
+}
|
@@ -131,7 +131,7 @@ Index: tracer.c
|
|
131
131
|
===================================================================
|
132
132
|
--- tracer.c (revision 0)
|
133
133
|
+++ tracer.c (revision 0)
|
134
|
-
@@ -0,0 +1,
|
134
|
+
@@ -0,0 +1,73 @@
|
135
135
|
+#include "ruby.h"
|
136
136
|
+
|
137
137
|
+#ifdef ENABLE_DTRACE
|
@@ -188,11 +188,22 @@ Index: tracer.c
|
|
188
188
|
+ return ret;
|
189
189
|
+}
|
190
190
|
+
|
191
|
+
+static VALUE
|
192
|
+
+ruby_dtrace_enabled(klass)
|
193
|
+
+ VALUE klass;
|
194
|
+
+{
|
195
|
+
+#ifdef ENABLE_DTRACE
|
196
|
+
+ return RUBY_RUBY_PROBE_ENABLED() ? Qtrue : Qfalse;
|
197
|
+
+#else
|
198
|
+
+ return Qfalse;
|
199
|
+
+#endif
|
200
|
+
+}
|
191
201
|
+
|
192
202
|
+void Init_Tracer()
|
193
203
|
+{
|
194
204
|
+ rb_mDtrace = rb_define_module("Tracer");
|
195
205
|
+ rb_define_module_function(rb_mDtrace, "fire", ruby_dtrace_fire, -1);
|
206
|
+
+ rb_define_module_function(rb_mDtrace, "enabled?", ruby_dtrace_enabled, 0);
|
196
207
|
+}
|
197
208
|
Index: dtrace.d
|
198
209
|
===================================================================
|
@@ -225,7 +236,7 @@ Index: dtrace.d
|
|
225
236
|
+#pragma D attributes Private/Private/Common provider ruby function
|
226
237
|
+#pragma D attributes Evolving/Evolving/Common provider ruby name
|
227
238
|
+#pragma D attributes Evolving/Evolving/Common provider ruby args
|
228
|
-
|
239
|
+
+
|
229
240
|
Index: common.mk
|
230
241
|
===================================================================
|
231
242
|
--- common.mk (revision 16089)
|
File without changes
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: XRay
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Philippe Hanrigou
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-
|
12
|
+
date: 2008-05-29 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -27,8 +27,8 @@ files:
|
|
27
27
|
- lib/xray/dtrace/rails/enable_tracing.rb
|
28
28
|
- lib/xray/dtrace/tracer.rb
|
29
29
|
- lib/xray/enable_thread_aware_dispatcher.rb
|
30
|
-
- lib/xray/rails_stack_signal_handler.rb
|
31
30
|
- lib/xray/thread_aware_dispatcher.rb
|
31
|
+
- lib/xray/thread_dump_signal_handler.rb
|
32
32
|
- lib/xray/xray.rb
|
33
33
|
- test/all_tests.rb
|
34
34
|
- test/functional/dtrace/tracer_test.rb
|
@@ -37,9 +37,11 @@ files:
|
|
37
37
|
- test/unit/thread_aware_dispatcher_test.rb
|
38
38
|
- test/unit/xray/dtrace/tracer_test.rb
|
39
39
|
- application-probes.d
|
40
|
-
-
|
41
|
-
- patch-for-
|
40
|
+
- patches_for_mri/caller_for_all_threads_patch_for_MRI_1.8.6.diff
|
41
|
+
- patches_for_mri/patch-for-dtrace-instrumentation-of-matz-1.8.6-p114.diff
|
42
|
+
- patches_for_mri/patch-for-joyent-mri-1.8.6-on-mac-os-x-leopard.diff
|
42
43
|
- gdb_macros
|
44
|
+
- Rakefile
|
43
45
|
- README
|
44
46
|
has_rdoc: true
|
45
47
|
homepage: http://xray.rubyforge.com
|
@@ -1,15 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# Install a signal handler dumping Rails stack by raising an exception
|
3
|
-
#
|
4
|
-
# Trigger it with: kill -QUIT <pid>
|
5
|
-
#
|
6
|
-
|
7
|
-
trap "QUIT" do
|
8
|
-
STDERR.puts "=============== XRay - Raising exception in Rails thread ==============="
|
9
|
-
if Dispatcher.thread_in_dispatch
|
10
|
-
Dispatcher.thread_in_dispatch.raise "XRay - Forced exception to Rails stack trace"
|
11
|
-
else
|
12
|
-
STDERR.puts "No Rails thread in dispatch"
|
13
|
-
end
|
14
|
-
STDERR.puts "=============== XRay - Done ==============="
|
15
|
-
end
|