trace_tree 0.1.5 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,14 @@
1
+ class TraceTree
2
+ class Point
3
+ class CcallKernelExtend < Point
4
+ def parameters
5
+ callees[0].mixin
6
+ end
7
+
8
+ def self.event_class_method
9
+ [:c_call, Kernel, :extend]
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,15 @@
1
+ class TraceTree
2
+ class Point
3
+ class CcallModuleAppendfeatures < Point
4
+
5
+ def self.event_class_method
6
+ [:c_call, Module, :append_features]
7
+ end
8
+
9
+ def parameters
10
+ terminal.return_value
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ class TraceTree
2
+ class Point
3
+ class CcallModuleExtendobject < Point
4
+
5
+ def mixin
6
+ terminal.mixin
7
+ end
8
+
9
+ def self.event_class_method
10
+ [:c_call, Module, :extend_object]
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ class TraceTree
2
+ class Point
3
+ class CcallModuleInclude < Point
4
+
5
+ def self.event_class_method
6
+ [:c_call, Module, :include]
7
+ end
8
+
9
+ def parameters
10
+ callees[0].parameters
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ class TraceTree
2
+ class Point
3
+ class CcallModulePrepend < Point
4
+
5
+ def self.event_class_method
6
+ [:c_call, Module, :prepend]
7
+ end
8
+
9
+ def parameters
10
+ callees[0].parameters
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ class TraceTree
2
+ class Point
3
+ class CcallModulePrependfeatures < Point
4
+
5
+ def self.event_class_method
6
+ [:c_call, Module, :prepend_features]
7
+ end
8
+
9
+ def parameters
10
+ terminal.return_value
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ class TraceTree
2
+ class Point
3
+ class CcallThreadInitialize < Point
4
+
5
+ def self.event_class_method
6
+ [:c_call, Thread, :initialize]
7
+ end
8
+
9
+ def callees
10
+ [terminal.thread_begin]
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,10 @@
1
+ class TraceTree
2
+ class Point
3
+ class Common < Point
4
+ def self.event_class_method
5
+ :common
6
+ end
7
+
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ class TraceTree
2
+ class Point
3
+ class CreturnClassthreadNew < Point
4
+
5
+ def self.event_class_method
6
+ [:c_return, Thread.singleton_class, :new]
7
+ end
8
+
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ class TraceTree
2
+ class Point
3
+ class CreturnModuleAppendfeatures < Point
4
+
5
+ def self.event_class_method
6
+ [:c_return, Module, :append_features]
7
+ end
8
+
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,18 @@
1
+ class TraceTree
2
+ class Point
3
+ class CreturnModuleExtendobject < Point
4
+
5
+ def initialize trace_point
6
+ super
7
+ @mixin = return_value.singleton_class.ancestors[1]
8
+ end
9
+
10
+ attr_reader :mixin
11
+
12
+ def self.event_class_method
13
+ [:c_return, Module, :extend_object]
14
+ end
15
+
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,11 @@
1
+ class TraceTree
2
+ class Point
3
+ class CreturnModulePrependfeatures < Point
4
+
5
+ def self.event_class_method
6
+ [:c_return, Module, :prepend_features]
7
+ end
8
+
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ class TraceTree
2
+ class Point
3
+ class CreturnThreadInitialize < Point
4
+
5
+ def self.event_class_method
6
+ [:c_return, Thread, :initialize]
7
+ end
8
+
9
+ attr_accessor :thread_begin
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,23 @@
1
+ class TraceTree
2
+ class Point
3
+ class Threadbegin < Point
4
+
5
+ def self.event_class_method
6
+ [:thread_begin, nil, nil]
7
+ end
8
+
9
+ def class_name
10
+ ''
11
+ end
12
+
13
+ def method_name
14
+ :thread_run
15
+ end
16
+
17
+ def call_symbol
18
+ ''
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,22 @@
1
+ class TraceTree
2
+ class Point
3
+ class Threadend < Point
4
+
5
+ def self.event_class_method
6
+ [:thread_end, nil, nil]
7
+ end
8
+
9
+ def class_name
10
+ ''
11
+ end
12
+
13
+ def method_name
14
+ :thread_run
15
+ end
16
+
17
+ def call_symbol
18
+ ''
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,168 @@
1
+ require 'trace_tree/tree_graphable'
2
+ require 'trace_tree/tree_htmlable'
3
+
4
+ class TraceTree
5
+ class Point
6
+
7
+ include TreeGraphable
8
+ include TreeHtmlable
9
+
10
+ attr_reader :current, :thread
11
+ attr_accessor :terminal
12
+
13
+ Interfaces = [:event, :defined_class, :method_id, :path, :lineno]
14
+ attr_reader *Interfaces
15
+
16
+ class << self
17
+ def inherited base
18
+ bases << base
19
+ end
20
+
21
+ def classes
22
+ @classes ||= bases.each_with_object(Hash.new{|h| h[:common]}){|c, h| h[c.event_class_method] = c}
23
+ end
24
+
25
+ def bases
26
+ @bases ||= []
27
+ end
28
+
29
+ def hashify point
30
+ attrs = Interfaces.each_with_object({}) do |attr, hash|
31
+ hash[attr] = point.send attr
32
+ end
33
+ attrs.merge!({return_value: point.return_value}) if point.event =~ /return/
34
+ attrs.merge!({thread: point.thread}) if point.respond_to? :thread
35
+ attrs
36
+ end
37
+
38
+ def class_of? point
39
+ [point.event, point.defined_class, point.method_id] == event_class_method
40
+ end
41
+
42
+ def initialize_clone proto
43
+ super.tap do
44
+ instance_variable_set :@proto, proto
45
+ end
46
+ end
47
+
48
+ attr_reader :proto
49
+ end
50
+
51
+ def method_missing method_id, *args, &blk
52
+ raise NoMethodError, "NoMethodError: undefined method `#{method_id}' for #<#{self.class.proto or self.class.name}#{inspect}>"
53
+ end
54
+
55
+ def initialize trace_point
56
+ Interfaces.each do |i|
57
+ instance_variable_set "@#{i}", trace_point.send(i)
58
+ end
59
+ @return_value = trace_point.return_value if x_return?
60
+ @current = trace_point.binding.of_callers[3] unless thread?
61
+ @thread = thread? ? trace_point.self : current.send(:eval, 'Thread.current')
62
+ rescue => e
63
+ puts e
64
+ end
65
+
66
+ def c_call?
67
+ event == :c_call
68
+ end
69
+
70
+ def x_return?
71
+ event =~ /return/
72
+ end
73
+
74
+ def thread?
75
+ event =~ /thread/
76
+ end
77
+
78
+ def return_value
79
+ raise RuntimeError.new('RuntimeError: not supported by this event') unless x_return?
80
+ @return_value
81
+ end
82
+
83
+ def inspect
84
+ to_h.inspect
85
+ end
86
+
87
+ def to_h
88
+ self.class.hashify(self)
89
+ end
90
+
91
+ def terminate? point
92
+ same_method?(point) and ending?(point)
93
+ end
94
+
95
+ def same_method? point
96
+ point.defined_class == defined_class and point.method_id == method_id
97
+ end
98
+
99
+ def ending? point
100
+ (event == :b_return and point.event == :b_call) or
101
+ (event == :c_return and point.event == :c_call) or
102
+ (event == :return and point.event == :call) or
103
+ (event == :end and point.event == :class) or
104
+ (event == :thread_end and point.event == :thread_begin)
105
+ end
106
+
107
+ def << node
108
+ callees << node
109
+ end
110
+
111
+ def callees
112
+ @callees ||= []
113
+ end
114
+
115
+ def class_and_method
116
+ "#{_class_and_method}#{arg}"
117
+ end
118
+
119
+ def _class_and_method
120
+ @km ||= "#{class_name}#{call_symbol}#{method_name}"
121
+ end
122
+
123
+ def class_name
124
+ c_call? ? defined_class : current.klass
125
+ rescue => e
126
+ puts event
127
+ end
128
+
129
+ def method_name
130
+ c_call? ? method_id : current.frame_env
131
+ end
132
+
133
+ def call_symbol
134
+ c_call? ? '#' : current.call_symbol
135
+ end
136
+
137
+ def source_location
138
+ "#{path}:#{lineno}"
139
+ end
140
+
141
+ def arg
142
+ respond_to?(:parameters) ? "(#{parameters})" : nil
143
+ end
144
+
145
+ class Loader
146
+
147
+ attr_reader :point_classes
148
+
149
+ def initialize *enhancement
150
+ return @point_classes = Point.classes if enhancement.empty?
151
+ @point_classes = Point.classes.each_with_object(Point.classes.dup) do |entry, hash|
152
+ hash[entry[0]] = entry[1].clone.prepend *enhancement
153
+ end
154
+ end
155
+
156
+ def create point
157
+ point_klass = point_classes[[point.event, point.defined_class, point.method_id]]
158
+ point_klass.new point
159
+ end
160
+ end
161
+
162
+ end
163
+ end
164
+
165
+ Dir.glob(File.expand_path('../point/*', __FILE__)).each do |concreate_point_path|
166
+ load concreate_point_path
167
+ #puts "---->#{concreate_point_path}"
168
+ end
@@ -4,12 +4,14 @@ class TraceTree
4
4
  module ShortGemPath
5
5
 
6
6
  def source_location
7
- "#{shorten_gem_path current.file}:#{current.line}"
7
+ #"#{shorten_gem_path current.file}:#{current.line}"
8
+ "#{shorten_gem_path path}:#{lineno}"
8
9
  end
9
10
 
10
11
  private
11
12
 
12
13
  def shorten_gem_path loc
14
+ return '' if loc.nil?
13
15
  GemPaths.each{|name, path| loc = loc.gsub(path, "$#{name}")}
14
16
  loc
15
17
  end
@@ -7,6 +7,8 @@ class TraceTree
7
7
 
8
8
  def label_for_tree_graph
9
9
  "#{class_and_method} #{source_location}"
10
+ #"#{defined_class}#{current.call_symbol}#{method_id} #{path} #{lineno}"
11
+ #"#{defined_class} #{method_id} #{path} #{lineno}"
10
12
  end
11
13
 
12
14
  def children_for_tree_graph
@@ -1,3 +1,3 @@
1
1
  class TraceTree
2
- VERSION = "0.1.5"
2
+ VERSION = "0.2.1"
3
3
  end
data/lib/trace_tree.rb CHANGED
@@ -1,10 +1,12 @@
1
1
  require "trace_tree/version"
2
2
  require 'binding_of_callers/pry'
3
- require 'trace_tree/node'
3
+ require 'trace_tree/point'
4
4
  require 'trace_tree/short_gem_path'
5
5
  require 'trace_tree/color'
6
6
  require 'trace_tree/tmp_file'
7
7
  require 'trace_tree/timer'
8
+ require 'thread'
9
+ require 'terminal-tableofhashes'
8
10
 
9
11
  class Binding
10
12
  def trace_tree *log, **opt, &to_do
@@ -14,75 +16,111 @@ end
14
16
 
15
17
  class TraceTree
16
18
 
19
+ Events = [:b_call, :b_return,
20
+ :c_call, :c_return,
21
+ :call, :return,
22
+ :class, :end,
23
+ :thread_begin, :thread_end]
24
+
17
25
  def initialize bi
18
26
  @bi = bi
19
- @trace_points = []
27
+ @trace_points = Queue.new
20
28
  @timer = Timer.new
21
29
  end
22
30
 
23
31
  def generate *log, **opt, &to_do
24
32
  @opt = opt
25
33
  @log = dump_location *log
26
- @node_class = optional_node **opt
34
+ enhance_point **opt
27
35
  @build_command = opt[:html] ? :tree_html_full : :tree_graph
28
- start_trace
29
- bi.eval('self').instance_eval &to_do
30
- ensure
31
- stop_trace
32
- end
33
-
34
- private
36
+ @ignore = opt[:ignore] || {}
37
+ here = bi.eval('self')
35
38
 
36
- attr_reader :bi, :trace_points, :log, :build_command, :timer, :opt
37
-
38
- def start_trace
39
+ #start_trace
39
40
  timer[:trace]
40
- @tp = TracePoint.trace(:call, :b_call, :raise, :c_call) do |point|
41
- trace_points << @node_class.new(point) if wanted? point
41
+ @tp = TracePoint.new(*Events) do |point|
42
+ trace_points << point_loader.create(point) if wanted? point
42
43
  end
43
- end
44
+ @tp.enable
44
45
 
45
- def stop_trace
46
+ here.instance_eval &to_do
47
+ ensure
48
+ #stop_trace
46
49
  return unless @tp
47
50
  @tp.disable
48
51
  timer[:trace]
49
52
  dump_trace_tree
50
53
  end
51
54
 
55
+ private
56
+
57
+ attr_reader :bi, :trace_points, :log, :build_command, :timer, :opt, :point_loader
58
+
52
59
  def dump_location *log
53
60
  return TmpFile.new opt[:tmp] if opt[:tmp]
54
61
  log.empty? ? STDOUT : log[0]
55
62
  end
56
63
 
57
- def optional_node opt
58
- Class.new TraceTree::Node do
59
- prepend TraceTree::ShortGemPath unless opt[:gem] == false
60
- prepend TraceTree::Color unless opt[:color] == false
61
- end
64
+ def enhance_point opt
65
+ enhancement = []
66
+ enhancement << TraceTree::Color unless opt[:color] == false
67
+ enhancement << TraceTree::ShortGemPath unless opt[:gem] == false
68
+ @point_loader = Point::Loader.new *enhancement
62
69
  end
63
70
 
64
71
  def dump_trace_tree
65
72
  timer[:tree]
66
- tree = sort(trace_points).send build_command
73
+ tree = sort(trace_points_array).send build_command
67
74
  timer[:tree]
68
75
  log.puts tree
69
76
  log.puts timer.to_s if opt[:timer]
77
+ rescue => e
78
+ log.puts timer.to_s
79
+ log.puts e
80
+ log.puts Terminal::Table.from_hashes trace_points_array.map(&:to_h)
70
81
  end
71
82
 
72
83
  def wanted? trace_point
73
- trace_point.event != :c_call or trace_point.method_id == :throw
84
+ @ignore.any? do |attr, pattern|
85
+ pattern =~ trace_point.send(attr)
86
+ end ? false : true
74
87
  end
75
88
 
76
- def sort stack
77
- hash = {}
78
- stack.each do |call|
79
- unless hash.empty?
80
- parent = hash[call.parent_stack]
81
- parent << call if parent
89
+ def sort trace_points
90
+ stacks = Hash.new{|h, thread| h[thread] = []}
91
+ initialized_threads, began_threads = {}, {}
92
+
93
+ trace_points.each do |point|
94
+ stack = stacks[point.thread]
95
+ unless stack.empty?
96
+ if point.terminate? stack.last
97
+ stack.last.terminal = point
98
+ stack.pop
99
+ else
100
+ stack.last << point
101
+ stack << point
102
+ end
103
+ else
104
+ stack << point
82
105
  end
83
- hash[call.whole_stack] = call
106
+ initialized_threads[point.return_value] = point if Point::CreturnThreadInitialize.class_of? point
107
+ began_threads[point.thread] = point if Point::Threadbegin.class_of? point
84
108
  end
85
- stack[0]
109
+
110
+ initialized_threads.each do |thread, point|
111
+ point.thread_begin = began_threads[thread]
112
+ end
113
+
114
+ stacks[trace_points.first.thread][0].
115
+ callees[0].
116
+ callees[0]
117
+ end
118
+
119
+ def trace_points_array
120
+ return @tpa if defined? @tpa
121
+ @tpa = []
122
+ @tpa << trace_points.deq until trace_points.size == 0
123
+ @tpa
86
124
  end
87
125
 
88
126
  end
data/trace_tree.gemspec CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ["ken"]
10
10
  spec.email = ["block24block@gmail.com"]
11
11
 
12
- spec.summary = %q{Print TracePoint(normal ruby call, block call, raise call, throw call) in tree graph}
12
+ spec.summary = %q{Print TracePoint(:b_call, :b_return, :c_call, :c_return, :call, :return, :class, :end, :thread_begin, :thread_end) in tree view, to console or html}
13
13
  spec.homepage = "https://github.com/turnon/trace_tree"
14
14
  spec.license = "MIT"
15
15
 
@@ -27,4 +27,6 @@ Gem::Specification.new do |spec|
27
27
  spec.add_dependency "binding_of_callers", "0.1.3"
28
28
  spec.add_dependency "tree_graph", "~> 0.2.0"
29
29
  spec.add_dependency "tree_html", "~> 0.1.0"
30
+ spec.add_dependency "activesupport", ">= 5.0.0"
31
+ spec.add_dependency "terminal-tableofhashes", "~> 0.1.0"
30
32
  end