XRay 1.0.1 → 1.0.3
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/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
|