rbtrace 0.3.4 → 0.3.5
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +1 -1
- data/README.md +6 -5
- data/bin/rbtrace +118 -43
- data/ext/rbtrace.c +159 -89
- data/rbtrace.gemspec +1 -1
- data/server.rb +13 -0
- data/test.sh +2 -0
- data/tracers/unicorn.tracer +1 -0
- metadata +5 -4
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -186,15 +186,16 @@ for popular ruby libraries and functions.
|
|
186
186
|
|
187
187
|
## todo
|
188
188
|
|
189
|
-
*
|
189
|
+
* write some real tests (that assert things)
|
190
|
+
* more expressive selectors (.*Controller#)
|
191
|
+
* include date in show time (-t)
|
192
|
+
* add --eval
|
193
|
+
* add --forkgdb
|
194
|
+
* add --strace mode/expression
|
190
195
|
* add triggers to start tracing slow methods only inside another method
|
191
196
|
* add watch expressions to fire tracers only when an expression is true
|
192
|
-
* syntax check expressions before adding them
|
193
197
|
* add special expressions for method args (_arg0_, _arguments_)
|
194
198
|
* optimize local variable lookup to avoid instance_eval
|
195
199
|
* run process via bin/rbtrace (to trace rubygems and bootup time)
|
196
|
-
* let bin/rbtrace attach to multiple pids
|
197
|
-
* how to select on multiple msgrcv() targets?
|
198
|
-
* prefix pid to output in multiple pid mode
|
199
200
|
* investigate mach_msg on osx since msgget(2) has hard kernel limits
|
200
201
|
|
data/bin/rbtrace
CHANGED
@@ -9,8 +9,13 @@ class String
|
|
9
9
|
end unless ''.respond_to?(:bytesize)
|
10
10
|
|
11
11
|
module FFI::LastError
|
12
|
+
Errnos = Errno::constants.map(&Errno.method(:const_get)).inject({}) do |hash, c|
|
13
|
+
hash[ c.const_get(:Errno) ] = c
|
14
|
+
hash
|
15
|
+
end
|
16
|
+
|
12
17
|
def self.exception
|
13
|
-
|
18
|
+
Errnos[error]
|
14
19
|
end
|
15
20
|
def self.raise(msg=nil)
|
16
21
|
Kernel.raise exception, msg
|
@@ -189,6 +194,13 @@ class RBTracer
|
|
189
194
|
send_cmd(:firehose)
|
190
195
|
end
|
191
196
|
|
197
|
+
# Turn on dev mode.
|
198
|
+
#
|
199
|
+
# Returns nothing.
|
200
|
+
def devmode
|
201
|
+
send_cmd(:devmode)
|
202
|
+
end
|
203
|
+
|
192
204
|
# Turn on GC tracing.
|
193
205
|
#
|
194
206
|
# Returns nothing.
|
@@ -207,15 +219,20 @@ class RBTracer
|
|
207
219
|
next if func.empty?
|
208
220
|
|
209
221
|
if func =~ /^(.+)\((.+)\)$/
|
210
|
-
|
222
|
+
name, args = $1, $2
|
211
223
|
args = args.split(',').map{ |a| a.strip }
|
212
224
|
end
|
213
225
|
|
214
|
-
send_cmd(:add, func)
|
226
|
+
send_cmd(:add, name || func)
|
215
227
|
|
216
|
-
args
|
217
|
-
|
218
|
-
|
228
|
+
if args and args.any?
|
229
|
+
args.each do |arg|
|
230
|
+
if (err = valid_syntax?(arg)) != true
|
231
|
+
raise ArgumentError, "#{err.class} for expression #{arg.inspect} in method #{func.inspect}"
|
232
|
+
end
|
233
|
+
send_cmd(:addexpr, arg)
|
234
|
+
end
|
235
|
+
end
|
219
236
|
end
|
220
237
|
end
|
221
238
|
|
@@ -252,6 +269,10 @@ class RBTracer
|
|
252
269
|
rescue Errno::EINVAL, Errno::EIDRM
|
253
270
|
puts
|
254
271
|
STDERR.puts "*** process #{pid} is gone"
|
272
|
+
STDERR.puts "*** #{$!.inspect}"
|
273
|
+
STDERR.puts $!.backtrace.join("\n ")
|
274
|
+
rescue Interrupt, SignalException
|
275
|
+
retry
|
255
276
|
end
|
256
277
|
|
257
278
|
# Process events from the traced process.
|
@@ -328,6 +349,14 @@ class RBTracer
|
|
328
349
|
retry
|
329
350
|
end
|
330
351
|
|
352
|
+
def valid_syntax?(code)
|
353
|
+
begin
|
354
|
+
eval("#{code}\nBEGIN {return true}", nil, 'rbtrace_expression', 0)
|
355
|
+
rescue Exception => e
|
356
|
+
e
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
331
360
|
def print(*args)
|
332
361
|
@out.print(*args)
|
333
362
|
end
|
@@ -499,8 +528,9 @@ class RBTracer
|
|
499
528
|
print "<%f>" % (diff/1_000_000.0)
|
500
529
|
end
|
501
530
|
puts
|
502
|
-
puts if nesting == 0
|
531
|
+
puts if nesting == 0 and @max_nesting > 1
|
503
532
|
|
533
|
+
@max_nesting = nesting if nesting > @max_nesting
|
504
534
|
@last_nesting = nesting
|
505
535
|
|
506
536
|
when 'gc'
|
@@ -532,7 +562,7 @@ class RBTracer
|
|
532
562
|
parser = Trollop::Parser.new do
|
533
563
|
version <<-EOS
|
534
564
|
rbtrace: like strace, but for ruby code
|
535
|
-
version 0.3.
|
565
|
+
version 0.3.5
|
536
566
|
(c) 2011 Aman Gupta (tmm1)
|
537
567
|
http://github.com/tmm1/rbtrace
|
538
568
|
EOS
|
@@ -585,7 +615,7 @@ All Options:\n
|
|
585
615
|
EOS
|
586
616
|
opt :pid,
|
587
617
|
"pid of the ruby process to trace",
|
588
|
-
:type => :
|
618
|
+
:type => :ints,
|
589
619
|
:short => '-p'
|
590
620
|
|
591
621
|
opt :firehose,
|
@@ -632,6 +662,9 @@ EOS
|
|
632
662
|
"config file",
|
633
663
|
:type => :strings,
|
634
664
|
:short => '-c'
|
665
|
+
|
666
|
+
opt :devmode,
|
667
|
+
"assume the ruby process is reloading classes and methods"
|
635
668
|
end
|
636
669
|
|
637
670
|
opts = Trollop.with_standard_exception_handling(parser) do
|
@@ -639,36 +672,23 @@ EOS
|
|
639
672
|
parser.parse(ARGV)
|
640
673
|
end
|
641
674
|
|
642
|
-
|
643
|
-
|
644
|
-
|
675
|
+
unless %w[ slow firehose methods config gc ].find{ |n| opts[:"#{n}_given"] }
|
676
|
+
$stderr.puts "Error: --slow, --gc, --firehose, --methods or --config required."
|
677
|
+
$stderr.puts "Try --help for help."
|
678
|
+
exit(-1)
|
645
679
|
end
|
646
680
|
|
647
|
-
|
648
|
-
firehose = nil
|
649
|
-
methods = nil
|
650
|
-
gc = nil
|
681
|
+
methods = []
|
651
682
|
|
652
|
-
if opts[:
|
653
|
-
|
683
|
+
if opts[:methods_given]
|
684
|
+
methods += opts[:methods]
|
654
685
|
end
|
655
686
|
|
656
|
-
if opts[:
|
657
|
-
slow = opts[:slow]
|
658
|
-
|
659
|
-
elsif opts[:firehose]
|
660
|
-
firehose = true
|
661
|
-
|
662
|
-
elsif opts[:methods]
|
663
|
-
methods = opts[:methods]
|
664
|
-
|
665
|
-
elsif opts[:config_given]
|
666
|
-
methods = []
|
667
|
-
|
687
|
+
if opts[:config_given]
|
668
688
|
Array(opts[:config]).each do |config|
|
669
689
|
file = [
|
670
690
|
config,
|
671
|
-
File.expand_path("../../tracers/#{config}.tracer",__FILE__)
|
691
|
+
File.expand_path("../../tracers/#{config}.tracer", __FILE__)
|
672
692
|
].find{ |f| File.exists?(f) }
|
673
693
|
|
674
694
|
unless file
|
@@ -683,30 +703,85 @@ EOS
|
|
683
703
|
methods << line
|
684
704
|
end
|
685
705
|
end
|
706
|
+
end
|
686
707
|
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
708
|
+
tracee = nil
|
709
|
+
|
710
|
+
if opts[:pid].size <= 1
|
711
|
+
tracee = opts[:pid].first
|
712
|
+
|
713
|
+
else
|
714
|
+
tracers = []
|
715
|
+
|
716
|
+
opts[:pid].each do |pid|
|
717
|
+
if child = fork
|
718
|
+
tracers << child
|
719
|
+
else
|
720
|
+
Process.setpgrp
|
721
|
+
STDIN.reopen '/dev/null'
|
722
|
+
$0 = "rbtrace -p #{pid} (parent: #{Process.ppid})"
|
723
|
+
|
724
|
+
opts[:output] += ".#{pid}" if opts[:output]
|
725
|
+
tracee = pid
|
726
|
+
|
727
|
+
# fall through and start tracing
|
728
|
+
break
|
729
|
+
end
|
730
|
+
end
|
731
|
+
|
732
|
+
if tracee.nil?
|
733
|
+
# this is the parent
|
734
|
+
while true
|
735
|
+
begin
|
736
|
+
break if tracers.empty?
|
737
|
+
if pid = Process.wait
|
738
|
+
tracers.delete(pid)
|
739
|
+
end
|
740
|
+
rescue Interrupt, SignalException
|
741
|
+
STDERR.puts "*** waiting on child tracers: #{tracers.inspect}"
|
742
|
+
tracers.each do |pid|
|
743
|
+
begin
|
744
|
+
Process.kill 'INT', pid
|
745
|
+
rescue Errno::ESRCH
|
746
|
+
end
|
747
|
+
end
|
748
|
+
end
|
749
|
+
end
|
750
|
+
|
751
|
+
exit!
|
752
|
+
end
|
753
|
+
end
|
754
|
+
|
755
|
+
if out = opts[:output]
|
756
|
+
output = File.open(out, opts[:append] ? 'a+' : 'w')
|
757
|
+
output.sync = true
|
691
758
|
end
|
692
759
|
|
693
760
|
begin
|
694
761
|
begin
|
695
|
-
tracer = RBTracer.new(
|
762
|
+
tracer = RBTracer.new(tracee)
|
696
763
|
rescue ArgumentError => e
|
697
764
|
parser.die :pid, "(#{e.message})"
|
698
765
|
end
|
699
766
|
|
700
|
-
if
|
767
|
+
if opts[:devmode_given]
|
768
|
+
tracer.devmode
|
769
|
+
end
|
770
|
+
|
771
|
+
if opts[:gc_given]
|
701
772
|
tracer.gc
|
702
773
|
end
|
703
774
|
|
704
|
-
if
|
705
|
-
tracer.watch(slow)
|
706
|
-
elsif firehose
|
775
|
+
if opts[:firehose_given]
|
707
776
|
tracer.firehose
|
708
|
-
|
709
|
-
|
777
|
+
else
|
778
|
+
if methods.any?
|
779
|
+
tracer.add(methods)
|
780
|
+
end
|
781
|
+
|
782
|
+
if opts[:slow_given]
|
783
|
+
tracer.watch(opts[:slow])
|
784
|
+
end
|
710
785
|
end
|
711
786
|
|
712
787
|
if output
|
@@ -719,7 +794,7 @@ EOS
|
|
719
794
|
|
720
795
|
begin
|
721
796
|
tracer.recv_loop
|
722
|
-
rescue Interrupt
|
797
|
+
rescue Interrupt, SignalException
|
723
798
|
end
|
724
799
|
ensure
|
725
800
|
if tracer
|
data/ext/rbtrace.c
CHANGED
@@ -57,8 +57,12 @@ timeofday_usec()
|
|
57
57
|
|
58
58
|
typedef struct {
|
59
59
|
int id;
|
60
|
-
|
61
60
|
char *query;
|
61
|
+
|
62
|
+
char *klass_name;
|
63
|
+
size_t klass_len;
|
64
|
+
bool is_singleton;
|
65
|
+
|
62
66
|
VALUE self;
|
63
67
|
VALUE klass;
|
64
68
|
ID mid;
|
@@ -79,6 +83,7 @@ static struct {
|
|
79
83
|
pid_t attached_pid;
|
80
84
|
|
81
85
|
bool installed;
|
86
|
+
bool devmode;
|
82
87
|
|
83
88
|
bool gc;
|
84
89
|
bool firehose;
|
@@ -106,6 +111,7 @@ rbtracer = {
|
|
106
111
|
.attached_pid = 0,
|
107
112
|
|
108
113
|
.installed = false,
|
114
|
+
.devmode = false,
|
109
115
|
|
110
116
|
.gc = false,
|
111
117
|
.firehose = false,
|
@@ -126,6 +132,10 @@ rbtracer = {
|
|
126
132
|
.msgpacker = NULL
|
127
133
|
};
|
128
134
|
|
135
|
+
static void
|
136
|
+
msgq_teardown(),
|
137
|
+
rbtracer_detach();
|
138
|
+
|
129
139
|
static inline void
|
130
140
|
rbtrace__send_event(int nargs, const char *name, ...)
|
131
141
|
{
|
@@ -160,38 +170,38 @@ rbtrace__send_event(int nargs, const char *name, ...)
|
|
160
170
|
for (n=0; n<nargs; n++) {
|
161
171
|
type = va_arg(ap, int);
|
162
172
|
switch (type) {
|
163
|
-
case '
|
164
|
-
uint64 = va_arg(ap, uint64_t);
|
165
|
-
msgpack_pack_uint64(pk, uint64);
|
166
|
-
break;
|
167
|
-
|
168
|
-
case 'n':
|
169
|
-
msgpack_pack_uint64(pk, timeofday_usec());
|
170
|
-
break;
|
171
|
-
|
172
|
-
case 'b':
|
173
|
+
case 'b': // boolean
|
173
174
|
if (va_arg(ap, int))
|
174
175
|
msgpack_pack_true(pk);
|
175
176
|
else
|
176
177
|
msgpack_pack_false(pk);
|
177
178
|
break;
|
178
179
|
|
179
|
-
case '
|
180
|
+
case 'd': // signed int
|
181
|
+
sint = va_arg(ap, int);
|
182
|
+
msgpack_pack_int(pk, sint);
|
183
|
+
break;
|
184
|
+
|
185
|
+
case 'u': // unsigned int
|
180
186
|
uint = va_arg(ap, uint32_t);
|
181
187
|
msgpack_pack_uint32(pk, uint);
|
182
188
|
break;
|
183
189
|
|
184
|
-
case 'l':
|
190
|
+
case 'l': // unsigned long (VALUE/ID)
|
185
191
|
ulong = va_arg(ap, unsigned long);
|
186
192
|
msgpack_pack_unsigned_long(pk, ulong);
|
187
193
|
break;
|
188
194
|
|
189
|
-
case '
|
190
|
-
|
191
|
-
|
195
|
+
case 't': // unsigned long long (timestamps)
|
196
|
+
uint64 = va_arg(ap, uint64_t);
|
197
|
+
msgpack_pack_uint64(pk, uint64);
|
192
198
|
break;
|
193
199
|
|
194
|
-
case '
|
200
|
+
case 'n': // current timestamp
|
201
|
+
msgpack_pack_uint64(pk, timeofday_usec());
|
202
|
+
break;
|
203
|
+
|
204
|
+
case 's': // string
|
195
205
|
str = va_arg(ap, char *);
|
196
206
|
if (!str)
|
197
207
|
str = (char *)"";
|
@@ -222,7 +232,12 @@ rbtrace__send_event(int nargs, const char *name, ...)
|
|
222
232
|
for (n=0; n<10 && ret==-1; n++)
|
223
233
|
ret = msgsnd(rbtracer.mqo_id, &msg, sizeof(msg)-sizeof(long), IPC_NOWAIT);
|
224
234
|
|
225
|
-
if (ret == -1 &&
|
235
|
+
if (ret == -1 && errno == EINVAL) {
|
236
|
+
fprintf(stderr, "msgsnd(%d): %s [detaching]\n", rbtracer.mqo_id, strerror(errno));
|
237
|
+
|
238
|
+
msgq_teardown();
|
239
|
+
rbtracer_detach();
|
240
|
+
} else if (ret == -1) {
|
226
241
|
fprintf(stderr, "msgsnd(%d): %s\n", rbtracer.mqo_id, strerror(errno));
|
227
242
|
|
228
243
|
struct msqid_ds stat;
|
@@ -259,35 +274,6 @@ rbtrace__send_names(ID mid, VALUE klass)
|
|
259
274
|
}
|
260
275
|
}
|
261
276
|
|
262
|
-
static void
|
263
|
-
rbtracer__resolve_query(char *query, VALUE *klass, VALUE *self, ID *mid)
|
264
|
-
{
|
265
|
-
char *idx = NULL, *method = NULL;
|
266
|
-
|
267
|
-
assert(klass && self && mid);
|
268
|
-
*klass = *self = *mid = 0;
|
269
|
-
|
270
|
-
if (NULL != (idx = rindex(query, '.'))) {
|
271
|
-
*idx = 0;
|
272
|
-
*self = rb_eval_string_protect(query, 0);
|
273
|
-
*idx = '.';
|
274
|
-
|
275
|
-
method = idx+1;
|
276
|
-
} else if (NULL != (idx = rindex(query, '#'))) {
|
277
|
-
*idx = 0;
|
278
|
-
*klass = rb_eval_string_protect(query, 0);
|
279
|
-
*idx = '#';
|
280
|
-
|
281
|
-
method = idx+1;
|
282
|
-
} else {
|
283
|
-
method = query;
|
284
|
-
}
|
285
|
-
|
286
|
-
if (method && *method) {
|
287
|
-
*mid = rb_intern(method);
|
288
|
-
}
|
289
|
-
}
|
290
|
-
|
291
277
|
static int in_event_hook = 0;
|
292
278
|
|
293
279
|
static void
|
@@ -326,7 +312,55 @@ event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
|
|
326
312
|
singleton = FL_TEST(klass, FL_SINGLETON);
|
327
313
|
}
|
328
314
|
|
329
|
-
|
315
|
+
rbtracer_t *tracer = NULL;
|
316
|
+
|
317
|
+
if (rbtracer.firehose) {
|
318
|
+
// trace everything
|
319
|
+
|
320
|
+
} else if (rbtracer.num > 0) {
|
321
|
+
// tracing only specific methods
|
322
|
+
int i, n;
|
323
|
+
for (i=0, n=0; i<MAX_TRACERS && n<rbtracer.num; i++) {
|
324
|
+
rbtracer_t *curr = &rbtracer.list[i];
|
325
|
+
|
326
|
+
if (curr->query) {
|
327
|
+
n++;
|
328
|
+
|
329
|
+
if (rbtracer.devmode) {
|
330
|
+
if ((!curr->mid || curr->mid == mid) &&
|
331
|
+
(!curr->klass_name || (
|
332
|
+
(singleton == curr->is_singleton) &&
|
333
|
+
(0 == strncmp(rb_class2name(singleton ? self : klass), curr->klass_name, curr->klass_len)))))
|
334
|
+
{
|
335
|
+
tracer = curr;
|
336
|
+
break;
|
337
|
+
}
|
338
|
+
} else {
|
339
|
+
if ((!curr->mid || curr->mid == mid) &&
|
340
|
+
(!curr->klass || curr->klass == klass) &&
|
341
|
+
(!curr->self || curr->self == self))
|
342
|
+
{
|
343
|
+
tracer = curr;
|
344
|
+
break;
|
345
|
+
}
|
346
|
+
}
|
347
|
+
}
|
348
|
+
}
|
349
|
+
|
350
|
+
// no tracer for current method call
|
351
|
+
if (!tracer) goto out;
|
352
|
+
|
353
|
+
} else if (rbtracer.slow) {
|
354
|
+
// trace anything that's slow
|
355
|
+
// fall through to slow logic below, after the previous conditional
|
356
|
+
// selects specific methods we might be interested in
|
357
|
+
|
358
|
+
} else {
|
359
|
+
// what are we doing here?
|
360
|
+
goto out;
|
361
|
+
}
|
362
|
+
|
363
|
+
// are we watching for slow method calls?
|
330
364
|
if (rbtracer.slow) {
|
331
365
|
uint64_t usec = timeofday_usec(), diff = 0;
|
332
366
|
|
@@ -366,34 +400,6 @@ event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
|
|
366
400
|
goto out;
|
367
401
|
}
|
368
402
|
|
369
|
-
int i, n;
|
370
|
-
rbtracer_t *tracer = NULL;
|
371
|
-
|
372
|
-
if (!rbtracer.firehose) {
|
373
|
-
// are there specific methods we're waiting for?
|
374
|
-
if (rbtracer.num == 0) goto out;
|
375
|
-
|
376
|
-
for (i=0, n=0; i<MAX_TRACERS && n<rbtracer.num; i++) {
|
377
|
-
rbtracer_t *curr = &rbtracer.list[i];
|
378
|
-
|
379
|
-
if (curr->query) {
|
380
|
-
n++;
|
381
|
-
|
382
|
-
if (!curr->mid || curr->mid == mid) {
|
383
|
-
if (!curr->klass || curr->klass == klass) {
|
384
|
-
if (!curr->self || curr->self == self) {
|
385
|
-
tracer = curr;
|
386
|
-
break;
|
387
|
-
}
|
388
|
-
}
|
389
|
-
}
|
390
|
-
}
|
391
|
-
}
|
392
|
-
|
393
|
-
// no matching method tracer found, so bail!
|
394
|
-
if (!tracer) goto out;
|
395
|
-
}
|
396
|
-
|
397
403
|
switch (event) {
|
398
404
|
case RUBY_EVENT_CALL:
|
399
405
|
case RUBY_EVENT_C_CALL:
|
@@ -408,6 +414,7 @@ event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
|
|
408
414
|
);
|
409
415
|
|
410
416
|
if (tracer && tracer->num_exprs) {
|
417
|
+
int i;
|
411
418
|
for (i=0; i<tracer->num_exprs; i++) {
|
412
419
|
char *expr = tracer->exprs[i];
|
413
420
|
size_t len = strlen(expr);
|
@@ -537,11 +544,14 @@ out:
|
|
537
544
|
}
|
538
545
|
|
539
546
|
static void
|
540
|
-
|
547
|
+
rbtracer_detach()
|
541
548
|
{
|
549
|
+
rbtracer.attached_pid = 0;
|
550
|
+
|
542
551
|
rbtracer.firehose = false;
|
543
552
|
rbtracer.slow = false;
|
544
553
|
rbtracer.gc = false;
|
554
|
+
rbtracer.devmode = false;
|
545
555
|
|
546
556
|
int i;
|
547
557
|
for (i=0; i<MAX_TRACERS; i++) {
|
@@ -577,22 +587,78 @@ rbtracer_add(char *query)
|
|
577
587
|
}
|
578
588
|
if (!tracer) goto out;
|
579
589
|
|
580
|
-
|
590
|
+
size_t
|
591
|
+
klass_begin = 0,
|
592
|
+
klass_end = 0;
|
593
|
+
|
594
|
+
bool is_singleton = false;
|
595
|
+
|
596
|
+
VALUE
|
597
|
+
klass = 0,
|
598
|
+
self = 0;
|
599
|
+
|
581
600
|
ID mid = 0;
|
582
601
|
|
583
|
-
|
602
|
+
{ // resolve query into its parts
|
603
|
+
char
|
604
|
+
*idx = NULL,
|
605
|
+
*method = NULL;
|
584
606
|
|
585
|
-
|
586
|
-
|
607
|
+
if (NULL != (idx = rindex(query, '.'))) {
|
608
|
+
klass_begin = 0;
|
609
|
+
klass_end = idx - query;
|
610
|
+
is_singleton = true;
|
611
|
+
|
612
|
+
*idx = 0;
|
613
|
+
if (!rbtracer.devmode)
|
614
|
+
self = rb_eval_string_protect(query, 0);
|
615
|
+
*idx = '.';
|
616
|
+
|
617
|
+
method = idx+1;
|
618
|
+
|
619
|
+
} else if (NULL != (idx = rindex(query, '#'))) {
|
620
|
+
klass_begin = 0;
|
621
|
+
klass_end = idx - query;
|
622
|
+
is_singleton = false;
|
623
|
+
|
624
|
+
*idx = 0;
|
625
|
+
if (!rbtracer.devmode)
|
626
|
+
klass = rb_eval_string_protect(query, 0);
|
627
|
+
*idx = '#';
|
628
|
+
|
629
|
+
method = idx+1;
|
630
|
+
|
631
|
+
} else {
|
632
|
+
method = query;
|
633
|
+
}
|
634
|
+
|
635
|
+
if (method && *method) {
|
636
|
+
mid = rb_intern(method);
|
637
|
+
}
|
638
|
+
}
|
639
|
+
|
640
|
+
if (rbtracer.devmode) {
|
641
|
+
if (!mid && (klass_begin == klass_end))
|
642
|
+
goto out;
|
643
|
+
} else {
|
644
|
+
if (!mid && !klass && !self)
|
645
|
+
goto out;
|
646
|
+
}
|
587
647
|
|
588
648
|
memset(tracer, 0, sizeof(*tracer));
|
589
649
|
|
590
650
|
tracer->id = tracer_id;
|
651
|
+
tracer->query = strdup(query);
|
652
|
+
|
653
|
+
if (klass_end != klass_begin) {
|
654
|
+
tracer->klass_name = tracer->query + klass_begin;
|
655
|
+
tracer->klass_len = klass_end - klass_begin;
|
656
|
+
}
|
657
|
+
tracer->is_singleton = is_singleton;
|
658
|
+
|
591
659
|
tracer->self = self;
|
592
660
|
tracer->klass = klass;
|
593
661
|
tracer->mid = mid;
|
594
|
-
tracer->query = strdup(query);
|
595
|
-
tracer->num_exprs = 0;
|
596
662
|
|
597
663
|
if (rbtracer.num == 0)
|
598
664
|
event_hook_install();
|
@@ -769,13 +835,14 @@ sigurg(int signal)
|
|
769
835
|
);
|
770
836
|
|
771
837
|
} else if (0 == strncmp("detach", str.ptr, str.size)) {
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
838
|
+
if (rbtracer.attached_pid) {
|
839
|
+
rbtrace__send_event(1,
|
840
|
+
"detached",
|
841
|
+
'u', (uint32_t) rbtracer.attached_pid
|
842
|
+
);
|
843
|
+
}
|
776
844
|
|
777
|
-
|
778
|
-
rbtracer_remove_all();
|
845
|
+
rbtracer_detach();
|
779
846
|
|
780
847
|
} else if (0 == strncmp("watch", str.ptr, str.size)) {
|
781
848
|
if (ary.size != 2 ||
|
@@ -814,6 +881,9 @@ sigurg(int signal)
|
|
814
881
|
} else if (0 == strncmp("gc", str.ptr, str.size)) {
|
815
882
|
rbtracer.gc = true;
|
816
883
|
|
884
|
+
} else if (0 == strncmp("devmode", str.ptr, str.size)) {
|
885
|
+
rbtracer.devmode = true;
|
886
|
+
|
817
887
|
}
|
818
888
|
}
|
819
889
|
}
|
data/rbtrace.gemspec
CHANGED
data/server.rb
CHANGED
@@ -7,6 +7,15 @@ class String
|
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
10
|
+
(reload_test = proc{
|
11
|
+
Object.send(:remove_const, :Test) if defined? Test
|
12
|
+
Test = Class.new do
|
13
|
+
def self.run
|
14
|
+
:abc
|
15
|
+
end
|
16
|
+
end
|
17
|
+
}).call
|
18
|
+
|
10
19
|
while true
|
11
20
|
proc {
|
12
21
|
Dir.chdir("/tmp") do
|
@@ -14,7 +23,11 @@ while true
|
|
14
23
|
Process.pid
|
15
24
|
'hello'.multiply_vowels(3){ :ohai }
|
16
25
|
sleep rand*0.5
|
26
|
+
|
17
27
|
GC.start
|
28
|
+
|
29
|
+
reload_test.call
|
30
|
+
Test.run
|
18
31
|
end
|
19
32
|
}.call
|
20
33
|
end
|
data/test.sh
CHANGED
@@ -30,6 +30,7 @@ trace() {
|
|
30
30
|
echo
|
31
31
|
}
|
32
32
|
|
33
|
+
trace -m Test.run --devmode
|
33
34
|
trace -m sleep
|
34
35
|
trace -m sleep Dir.chdir Dir.pwd Process.pid "String#gsub" "String#*"
|
35
36
|
trace -m "Kernel#"
|
@@ -37,6 +38,7 @@ trace -m "String#gsub(self,@test)" "String#*(self,__source__)" "String#multiply_
|
|
37
38
|
trace --gc --slow=200
|
38
39
|
trace --gc -m Dir.
|
39
40
|
trace --slow=250
|
41
|
+
trace --slow=250 -m sleep
|
40
42
|
trace --firehose
|
41
43
|
|
42
44
|
cleanup
|
@@ -0,0 +1 @@
|
|
1
|
+
Unicorn::App::OldRails#call(env['PATH_INFO'])
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rbtrace
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 25
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 3
|
9
|
-
-
|
10
|
-
version: 0.3.
|
9
|
+
- 5
|
10
|
+
version: 0.3.5
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Aman Gupta
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-02-
|
18
|
+
date: 2011-02-21 00:00:00 -08:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -91,6 +91,7 @@ files:
|
|
91
91
|
- tracers/eventmachine.tracer
|
92
92
|
- tracers/io.tracer
|
93
93
|
- tracers/redis.tracer
|
94
|
+
- tracers/unicorn.tracer
|
94
95
|
has_rdoc: true
|
95
96
|
homepage: http://github.com/tmm1/rbtrace
|
96
97
|
licenses: []
|