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 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: []