rbtrace 0.3.8 → 0.3.9

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.8)
4
+ rbtrace (0.3.9)
5
5
  ffi (>= 1.0.5)
6
6
  msgpack (>= 0.4.3)
7
7
  trollop (>= 1.16.2)
data/bin/rbtrace CHANGED
@@ -123,6 +123,9 @@ class RBTracer
123
123
  # Public: The IO where tracing output is written (default: STDOUT).
124
124
  attr_accessor :out
125
125
 
126
+ # Public: The timeout before giving up on attaching/detaching to a process.
127
+ attr_accessor :timeout
128
+
126
129
  # The String prefix used on nested method calls (default: ' ').
127
130
  attr_accessor :prefix
128
131
 
@@ -176,7 +179,10 @@ class RBTracer
176
179
  @max_nesting = @last_nesting = @nesting = 0
177
180
  @last_tracer = nil
178
181
 
182
+ @timeout = 5
183
+
179
184
  @out = STDOUT
185
+ @out.sync = true
180
186
  @prefix = ' '
181
187
  @printed_newline = true
182
188
 
@@ -216,7 +222,7 @@ class RBTracer
216
222
  # Returns a Fixnum pid.
217
223
  def fork
218
224
  send_cmd(:fork)
219
- if wait_for(30, 'for fork'){ !!@forked_pid }
225
+ if wait('for fork', 30){ !!@forked_pid }
220
226
  @forked_pid
221
227
  else
222
228
  STDERR.puts '*** timed out waiting for fork'
@@ -233,7 +239,7 @@ class RBTracer
233
239
 
234
240
  send_cmd(:eval, code)
235
241
 
236
- if wait_for(10, 'for eval response'){ !!@eval_result }
242
+ if wait('for eval response', 15){ !!@eval_result }
237
243
  @eval_result
238
244
  else
239
245
  STDERR.puts '*** timed out waiting for eval response'
@@ -247,28 +253,42 @@ class RBTracer
247
253
  send_cmd(:gc)
248
254
  end
249
255
 
256
+ # Restrict slow tracing to a specific list of methods.
257
+ #
258
+ # methods - The String or Array of method selectors.
259
+ #
260
+ # Returns nothing.
261
+ def add_slow(methods)
262
+ add(methods, true)
263
+ end
264
+
250
265
  # Add tracers for the given list of methods.
251
266
  #
252
267
  # methods - The String or Array of method selectors to trace.
253
268
  #
254
269
  # Returns nothing.
255
- def add(methods)
270
+ def add(methods, slow=false)
256
271
  Array(methods).each do |func|
257
272
  func = func.strip
258
273
  next if func.empty?
259
274
 
260
- if func =~ /^(.+)\((.+)\)$/
275
+ if func =~ /^(.+?)\((.+)\)$/
261
276
  name, args = $1, $2
262
277
  args = args.split(',').map{ |a| a.strip }
263
278
  end
264
279
 
265
- send_cmd(:add, name || func)
280
+ send_cmd(:add, name || func, slow)
266
281
 
267
282
  if args and args.any?
268
283
  args.each do |arg|
269
284
  if (err = valid_syntax?(arg)) != true
270
285
  raise ArgumentError, "#{err.class} for expression #{arg.inspect} in method #{func.inspect}"
271
286
  end
287
+ if arg =~ /^@/ and arg !~ /^@[_a-z][_a-z0-9]+$/i
288
+ # arg[0]=='@' means ivar, but if this is an expr
289
+ # we can hack a space in front so it gets eval'd instead
290
+ arg = " #{arg}"
291
+ end
272
292
  send_cmd(:addexpr, arg)
273
293
  end
274
294
  end
@@ -280,7 +300,7 @@ class RBTracer
280
300
  # Returns nothing.
281
301
  def attach
282
302
  send_cmd(:attach, Process.pid)
283
- if wait_for{ @attached == true }
303
+ if wait('to attach'){ @attached == true }
284
304
  STDERR.puts "*** attached to process #{pid}"
285
305
  else
286
306
  raise ArgumentError, 'process already being traced?'
@@ -298,7 +318,7 @@ class RBTracer
298
318
 
299
319
  newline
300
320
 
301
- if wait_for{ @attached == false }
321
+ if wait('to detach cleanly'){ @attached == false }
302
322
  newline
303
323
  STDERR.puts "*** detached from process #{pid}"
304
324
  else
@@ -358,13 +378,18 @@ class RBTracer
358
378
  # block - The Block that is checked every 50ms until it returns true.
359
379
  #
360
380
  # Returns true when the condition was met, or false on a timeout.
361
- def wait_for(time=5, reason='to detach cleanly')
381
+ def wait(reason, time=@timeout)
362
382
  wait = 0.05 # polling interval
363
383
 
364
384
  (time/wait).to_i.times do
365
385
  begin
366
386
  recv_lines
367
387
  sleep(wait)
388
+ begin
389
+ signal
390
+ rescue Errno::ESRCH
391
+ break
392
+ end
368
393
  time -= wait
369
394
 
370
395
  return true if yield
@@ -491,7 +516,7 @@ class RBTracer
491
516
  tracer = @tracers[tracer_id]
492
517
 
493
518
  if expr_id > -1
494
- tracer[:exprs][expr_id] = expr
519
+ tracer[:exprs][expr_id] = expr.strip
495
520
  end
496
521
 
497
522
  when 'exprval'
@@ -554,7 +579,7 @@ class RBTracer
554
579
  print ')' if @last_tracer and @last_tracer[:arglist]
555
580
 
556
581
  unless tracer == @last_tracer and @last_tracer[:last] == name
557
- puts
582
+ newline
558
583
  print ' '*16 if @show_time
559
584
  print @prefix*@nesting if @nesting > 0
560
585
  print name
@@ -578,6 +603,9 @@ class RBTracer
578
603
  name = klass ? "#{klass}#{ is_singleton ? '.' : '#' }" : ''
579
604
  name += @methods[mid] || '(unknown)'
580
605
 
606
+ newline
607
+ nesting = @nesting if @nesting > 0
608
+
581
609
  if @show_time
582
610
  t = Time.at(time/1_000_000)
583
611
  print t.strftime("%H:%M:%S.")
@@ -599,7 +627,7 @@ class RBTracer
599
627
  when 'gc'
600
628
  time, = *cmd
601
629
 
602
- puts unless @watch_slow
630
+ newline
603
631
  if @show_time
604
632
  t = Time.at(time/1_000_000)
605
633
  print t.strftime("%H:%M:%S.")
@@ -625,7 +653,7 @@ class RBTracer
625
653
  parser = Trollop::Parser.new do
626
654
  version <<-EOS
627
655
  rbtrace: like strace, but for ruby code
628
- version 0.3.8
656
+ version 0.3.9
629
657
  (c) 2011 Aman Gupta (tmm1)
630
658
  http://github.com/tmm1/rbtrace
631
659
  EOS
@@ -690,6 +718,10 @@ EOS
690
718
  :default => 250,
691
719
  :short => '-s'
692
720
 
721
+ opt :slow_methods,
722
+ "method(s) to restrict --slow to",
723
+ :type => :strings
724
+
693
725
  opt :methods,
694
726
  "method(s) to trace (valid formats: sleep String#gsub Process.pid Kernel# Dir.)",
695
727
  :type => :strings,
@@ -736,6 +768,10 @@ EOS
736
768
  "evaluate a ruby expression in the process",
737
769
  :type => String,
738
770
  :short => '-e'
771
+
772
+ opt :timeout,
773
+ "seconds to wait before giving up on attach/detach",
774
+ :default => 5
739
775
  end
740
776
 
741
777
  opts = Trollop.with_standard_exception_handling(parser) do
@@ -753,11 +789,14 @@ EOS
753
789
  parser.die :fork, '(can only be invoked with one pid)'
754
790
  end
755
791
 
756
- methods = []
792
+ methods, smethods = [], []
757
793
 
758
794
  if opts[:methods_given]
759
795
  methods += opts[:methods]
760
796
  end
797
+ if opts[:slow_methods_given]
798
+ smethods += opts[:slow_methods]
799
+ end
761
800
 
762
801
  if opts[:config_given]
763
802
  Array(opts[:config]).each do |config|
@@ -851,6 +890,7 @@ EOS
851
890
 
852
891
  else
853
892
  tracer.out = output if output
893
+ tracer.timeout = opts[:timeout] if opts[:timeout] > 0
854
894
  tracer.prefix = ' ' * opts[:prefix]
855
895
  tracer.show_time = opts[:start_time]
856
896
  tracer.show_duration = !opts[:no_duration]
@@ -862,7 +902,10 @@ EOS
862
902
  tracer.firehose
863
903
  else
864
904
  tracer.add(methods) if methods.any?
865
- tracer.watch(opts[:slow]) if opts[:slow_given]
905
+ if opts[:slow_given]
906
+ tracer.watch(opts[:slow])
907
+ tracer.add_slow(smethods) if smethods.any?
908
+ end
866
909
  end
867
910
  begin
868
911
  tracer.recv_loop
data/ext/extconf.rb CHANGED
@@ -22,7 +22,7 @@ unless File.exists?("#{CWD}/dst/lib/libmsgpackc.a")
22
22
 
23
23
  sys("tar zxvf #{msgpack}")
24
24
  Dir.chdir(dir) do
25
- sys("./configure --disable-shared --with-pic --prefix=#{CWD}/dst/")
25
+ sys("./configure --disable-shared --disable-cxx --with-pic --prefix=#{CWD}/dst/")
26
26
  sys("make install")
27
27
  end
28
28
  end
data/ext/rbtrace.c CHANGED
@@ -54,6 +54,7 @@ timeofday_usec()
54
54
  typedef struct {
55
55
  int id;
56
56
  char *query;
57
+ bool is_slow;
57
58
 
58
59
  char *klass_name;
59
60
  size_t klass_len;
@@ -331,6 +332,9 @@ event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
331
332
  if (curr->query) {
332
333
  n++;
333
334
 
335
+ // there should never be slow method tracers outside slow mode
336
+ if (!rbtracer.slow && curr->is_slow) continue;
337
+
334
338
  if (rbtracer.devmode) {
335
339
  if ((!curr->mid || curr->mid == mid) &&
336
340
  (!curr->klass_name || (
@@ -366,7 +370,7 @@ event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
366
370
  }
367
371
 
368
372
  // are we watching for slow method calls?
369
- if (rbtracer.slow) {
373
+ if (rbtracer.slow && (!tracer || tracer->is_slow)) {
370
374
  uint64_t usec = timeofday_usec(), diff = 0;
371
375
 
372
376
  switch (event) {
@@ -481,7 +485,7 @@ event_hook_install()
481
485
  event_hook,
482
486
  RUBY_EVENT_CALL | RUBY_EVENT_C_CALL |
483
487
  RUBY_EVENT_RETURN | RUBY_EVENT_C_RETURN
484
- #ifdef RB_EVENT_HOOKS_HAVE_CALLBACK_DATA
488
+ #ifdef RUBY_VM
485
489
  , 0
486
490
  #endif
487
491
  );
@@ -575,7 +579,7 @@ rbtracer_detach()
575
579
  }
576
580
 
577
581
  static int
578
- rbtracer_add(char *query)
582
+ rbtracer_add(char *query, bool is_slow)
579
583
  {
580
584
  int i;
581
585
  int tracer_id = -1;
@@ -654,6 +658,7 @@ rbtracer_add(char *query)
654
658
 
655
659
  tracer->id = tracer_id;
656
660
  tracer->query = strdup(query);
661
+ tracer->is_slow = is_slow;
657
662
 
658
663
  if (klass_end != klass_begin) {
659
664
  tracer->klass_name = tracer->query + klass_begin;
@@ -834,15 +839,17 @@ rbtrace__process_event(msgpack_object cmd)
834
839
  event_hook_install();
835
840
 
836
841
  } else if (0 == strncmp("add", str.ptr, str.size)) {
837
- if (ary.size != 2 ||
838
- ary.ptr[1].type != MSGPACK_OBJECT_RAW)
842
+ if (ary.size != 3 ||
843
+ ary.ptr[1].type != MSGPACK_OBJECT_RAW ||
844
+ ary.ptr[2].type != MSGPACK_OBJECT_BOOLEAN)
839
845
  return;
840
846
 
841
847
  str = ary.ptr[1].via.raw;
848
+ bool is_slow = ary.ptr[2].via.boolean;
842
849
 
843
850
  strncpy(query, str.ptr, str.size);
844
851
  query[str.size] = 0;
845
- last_tracer_id = rbtracer_add(query);
852
+ last_tracer_id = rbtracer_add(query, is_slow);
846
853
 
847
854
  } else if (0 == strncmp("addexpr", str.ptr, str.size)) {
848
855
  if (ary.size != 2 ||
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.8'
3
+ s.version = '0.3.9'
4
4
  s.homepage = 'http://github.com/tmm1/rbtrace'
5
5
 
6
6
  s.authors = 'Aman Gupta'
data/test.sh CHANGED
@@ -38,7 +38,8 @@ trace -m "String#gsub(self,@test)" "String#*(self,__source__)" "String#multiply_
38
38
  trace --gc --slow=200
39
39
  trace --gc -m Dir.
40
40
  trace --slow=250
41
- trace --slow=250 -m sleep
41
+ trace --slow=250 --slow-methods sleep
42
+ trace --gc -m Dir. --slow=250 --slow-methods sleep
42
43
  trace --firehose
43
44
 
44
45
  cleanup
@@ -0,0 +1 @@
1
+ Test::Unit::TestSuite#run(name, size)
metadata CHANGED
@@ -1,12 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rbtrace
3
3
  version: !ruby/object:Gem::Version
4
- prerelease: false
4
+ hash: 1
5
+ prerelease:
5
6
  segments:
6
7
  - 0
7
8
  - 3
8
- - 8
9
- version: 0.3.8
9
+ - 9
10
+ version: 0.3.9
10
11
  platform: ruby
11
12
  authors:
12
13
  - Aman Gupta
@@ -14,7 +15,7 @@ autorequire:
14
15
  bindir: bin
15
16
  cert_chain: []
16
17
 
17
- date: 2011-02-22 00:00:00 -08:00
18
+ date: 2011-02-25 00:00:00 -08:00
18
19
  default_executable:
19
20
  dependencies:
20
21
  - !ruby/object:Gem::Dependency
@@ -25,6 +26,7 @@ dependencies:
25
26
  requirements:
26
27
  - - ">="
27
28
  - !ruby/object:Gem::Version
29
+ hash: 29
28
30
  segments:
29
31
  - 1
30
32
  - 0
@@ -40,6 +42,7 @@ dependencies:
40
42
  requirements:
41
43
  - - ">="
42
44
  - !ruby/object:Gem::Version
45
+ hash: 83
43
46
  segments:
44
47
  - 1
45
48
  - 16
@@ -55,6 +58,7 @@ dependencies:
55
58
  requirements:
56
59
  - - ">="
57
60
  - !ruby/object:Gem::Version
61
+ hash: 9
58
62
  segments:
59
63
  - 0
60
64
  - 4
@@ -88,6 +92,7 @@ files:
88
92
  - tracers/io.tracer
89
93
  - tracers/mongo.tracer
90
94
  - tracers/redis.tracer
95
+ - tracers/testunit.tracer
91
96
  - tracers/unicorn.tracer
92
97
  has_rdoc: true
93
98
  homepage: http://github.com/tmm1/rbtrace
@@ -103,6 +108,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
103
108
  requirements:
104
109
  - - ">="
105
110
  - !ruby/object:Gem::Version
111
+ hash: 3
106
112
  segments:
107
113
  - 0
108
114
  version: "0"
@@ -111,13 +117,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
111
117
  requirements:
112
118
  - - ">="
113
119
  - !ruby/object:Gem::Version
120
+ hash: 3
114
121
  segments:
115
122
  - 0
116
123
  version: "0"
117
124
  requirements: []
118
125
 
119
126
  rubyforge_project:
120
- rubygems_version: 1.3.7
127
+ rubygems_version: 1.4.2
121
128
  signing_key:
122
129
  specification_version: 3
123
130
  summary: "rbtrace: like strace but for ruby code"