rbtrace 0.3.4 → 0.3.5

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/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rbtrace (0.3.4)
4
+ rbtrace (0.3.5)
5
5
  ffi (>= 1.0.5)
6
6
  msgpack (>= 0.4.3)
7
7
  trollop (>= 1.16.2)
data/README.md CHANGED
@@ -186,15 +186,16 @@ for popular ruby libraries and functions.
186
186
 
187
187
  ## todo
188
188
 
189
- * allow slow tracing of specific methods (--slow + --methods)
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
- Errno::constants.map(&Errno.method(:const_get)).find{ |c| c.const_get(:Errno) == error }
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
- func, args = $1, $2
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.each do |arg|
217
- send_cmd(:addexpr, arg)
218
- end if args and args.any?
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.4
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 => :int,
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
- if out = opts[:output]
643
- output = File.open(out, opts[:append] ? 'a+' : 'w')
644
- output.sync = true
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
- slow = nil
648
- firehose = nil
649
- methods = nil
650
- gc = nil
681
+ methods = []
651
682
 
652
- if opts[:gc_given]
653
- gc = true
683
+ if opts[:methods_given]
684
+ methods += opts[:methods]
654
685
  end
655
686
 
656
- if opts[:slow_given]
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
- elsif !gc
688
- $stderr.puts "Error: --slow, --gc, --firehose, --methods or --config required."
689
- $stderr.puts "Try --help for help."
690
- exit(-1)
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(opts[:pid])
762
+ tracer = RBTracer.new(tracee)
696
763
  rescue ArgumentError => e
697
764
  parser.die :pid, "(#{e.message})"
698
765
  end
699
766
 
700
- if gc
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 slow
705
- tracer.watch(slow)
706
- elsif firehose
775
+ if opts[:firehose_given]
707
776
  tracer.firehose
708
- elsif methods
709
- tracer.add(methods)
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 't':
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 'u':
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 'd':
190
- sint = va_arg(ap, int);
191
- msgpack_pack_int(pk, sint);
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 's':
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 && rbtracer.mqo_id != -1 && errno != EINVAL) {
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
- // are we watching for any slow methods?
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
- rbtracer_remove_all()
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
- VALUE klass = 0, self = 0;
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
- rbtracer__resolve_query(query, &klass, &self, &mid);
602
+ { // resolve query into its parts
603
+ char
604
+ *idx = NULL,
605
+ *method = NULL;
584
606
 
585
- if (!mid && !klass && !self)
586
- goto out;
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
- rbtrace__send_event(1,
773
- "detached",
774
- 'u', (uint32_t) rbtracer.attached_pid
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
- rbtracer.attached_pid = 0;
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
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'rbtrace'
3
- s.version = '0.3.4'
3
+ s.version = '0.3.5'
4
4
  s.homepage = 'http://github.com/tmm1/rbtrace'
5
5
 
6
6
  s.authors = 'Aman Gupta'
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: 27
4
+ hash: 25
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 3
9
- - 4
10
- version: 0.3.4
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-19 00:00:00 -08:00
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: []