rbtrace 0.3.8 → 0.3.9

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.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"