trace_tree 0.1.5 → 0.2.1

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