method_call_tracer 0.1.0 → 0.2.0
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.
- checksums.yaml +4 -4
- data/README.md +4 -2
- data/lib/generators/method_tracer/templates/initializer.rb +2 -0
- data/lib/method_tracer/tracer.rb +20 -74
- data/lib/method_tracer/version.rb +1 -1
- data/method_tracer.gemspec +3 -1
- metadata +18 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5ec122bd2856f55ddd0958f690f667cfac0dd6d0
|
4
|
+
data.tar.gz: c517dc70ab2c883d8acc5e8b32e78a833c0565ba
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f1f235d6fe985239be47614b1bcfd9a925c157152de974d7dabf071d0cf36a024dbc63f37db9b9bbfc71351faec6cfd0b93d5fef9874916199e456e1b26366a2
|
7
|
+
data.tar.gz: 672b73d90ab60177d87b3f0a67ab828800154e077c20cdc51facc2178637ba3ff015731e7bf85a13c53d844827406218c61575799a114f335c7869272af34a01
|
data/README.md
CHANGED
@@ -4,6 +4,8 @@ MethodTracer is a tool for detecting lines in an application that call certain m
|
|
4
4
|
|
5
5
|
<sup>1</sup> Designating traced methods by file lets you trace methods defined in the "namespace" of a different gem. For example, if a hypothetical gem `activerecord-extension` defines some methods on the class `ActiveRecord`, we still have the ability to trace only the methods from `activerecord-extension` without capturing the methods from `activerecord`.
|
6
6
|
|
7
|
+
**Note about gem name**: due to a naming collision on rubygems.org, this gem appears there as `method_call_tracer`.
|
8
|
+
|
7
9
|
## Usage
|
8
10
|
|
9
11
|
To attach tracers to methods, instantiate `MethodTracer::Tracer` objects. For Rails applications, these can be placed in the provided initializer.
|
@@ -35,7 +37,7 @@ MethodTracer theoretically does not interfere with the original behavior of meth
|
|
35
37
|
Add this line to your application's Gemfile:
|
36
38
|
|
37
39
|
```ruby
|
38
|
-
gem '
|
40
|
+
gem 'method_call_tracer'
|
39
41
|
```
|
40
42
|
|
41
43
|
And then execute:
|
@@ -44,7 +46,7 @@ And then execute:
|
|
44
46
|
|
45
47
|
Or install it yourself as:
|
46
48
|
|
47
|
-
$ gem install
|
49
|
+
$ gem install method_call_tracer
|
48
50
|
|
49
51
|
If you are using it with Rails, run the installation generator to install an example config initializer:
|
50
52
|
|
data/lib/method_tracer/tracer.rb
CHANGED
@@ -1,37 +1,28 @@
|
|
1
|
+
require 'where_is'
|
2
|
+
|
1
3
|
module MethodTracer
|
2
4
|
class Tracer
|
3
|
-
UNCOOPERATIVE_NAMES = [
|
4
|
-
# Some classes don't behave well when we try to hook them, at least with
|
5
|
-
# the methods currently used.
|
6
|
-
'CGI', # Waits for input from stdin when opening rails console
|
7
|
-
'RSpec' # RSpec doesn't run
|
8
|
-
].freeze
|
9
|
-
|
10
5
|
def initialize(target)
|
11
6
|
@target_path = target
|
12
7
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
add_hooks_to_instance_methods
|
8
|
+
@tracer = TracePoint.trace(:call) do |tp|
|
9
|
+
record_call_if_interesting(tp)
|
10
|
+
end
|
17
11
|
end
|
18
12
|
|
19
|
-
def
|
20
|
-
|
21
|
-
UNCOOPERATIVE_NAMES.any? { |bad_name| class_name.include?(bad_name) }
|
22
|
-
end
|
13
|
+
def record_call_if_interesting(tp)
|
14
|
+
return unless class_is_interesting?(tp.defined_class)
|
23
15
|
|
24
|
-
|
25
|
-
|
26
|
-
caller_locations.select { |loc| loc.path.start_with?(Config.app_path) }
|
27
|
-
.each do |loc|
|
28
|
-
outfile.write "#{loc.path}:#{loc.lineno}\n"
|
29
|
-
end
|
16
|
+
locations = caller_locations.select { |loc| loc.path.start_with?(Config.app_path) }
|
17
|
+
return if locations.empty?
|
30
18
|
|
31
|
-
|
19
|
+
outfile.write "#{@target_path} :#{tp.method_id}\n"
|
20
|
+
locations.each do |loc|
|
21
|
+
outfile.write "#{loc.path}:#{loc.lineno}\n"
|
22
|
+
end
|
32
23
|
end
|
33
24
|
|
34
|
-
def
|
25
|
+
def outfile
|
35
26
|
@outfile ||= begin
|
36
27
|
output_file = Config.output_file
|
37
28
|
if output_file.instance_of?(IO) || output_file.instance_of?(StringIO)
|
@@ -44,58 +35,13 @@ module MethodTracer
|
|
44
35
|
end
|
45
36
|
end
|
46
37
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
receiver = m.receiver
|
53
|
-
|
54
|
-
receiver.send(:define_singleton_method, unbound_m.name) do |*args, &block|
|
55
|
-
Tracer.record_and_call_original(unbound_m, receiver, *args, &block)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
def add_hooks_to_instance_methods
|
61
|
-
methods_of_interest(@all_instance_methods).each do |m|
|
62
|
-
unbound_m = m.unbind
|
63
|
-
receiver = m.receiver
|
64
|
-
|
65
|
-
receiver.class.send(:define_method, m.name) do |*args, &block|
|
66
|
-
Tracer.record_and_call_original(unbound_m, receiver, *args, &block)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def find_methods!
|
72
|
-
@all_class_methods = []
|
73
|
-
@all_instance_methods = []
|
74
|
-
ObjectSpace.each_object(Class) do |defined_class|
|
75
|
-
next if Tracer.uncooperative_class?(defined_class.name)
|
76
|
-
|
77
|
-
defined_class.methods(false).each do |method_sym|
|
78
|
-
@all_class_methods << defined_class.method(method_sym)
|
79
|
-
end
|
80
|
-
|
81
|
-
begin
|
82
|
-
instance = defined_class.new
|
83
|
-
defined_class.instance_methods(false).each do |method_sym|
|
84
|
-
@all_instance_methods << instance.method(method_sym)
|
85
|
-
end
|
86
|
-
rescue StandardError, NotImplementedError, LoadError
|
87
|
-
# If the class isn't instantiable, skip it
|
88
|
-
next
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
def methods_of_interest(methods)
|
94
|
-
methods.select do |m|
|
95
|
-
m.instance_of?(Method) &&
|
96
|
-
!m.source_location.nil? &&
|
97
|
-
m.source_location[0].start_with?(@target_path)
|
38
|
+
def class_is_interesting?(candidate_class)
|
39
|
+
begin
|
40
|
+
location = Where.is(candidate_class)
|
41
|
+
rescue NameError
|
42
|
+
return false
|
98
43
|
end
|
44
|
+
location[:file].start_with?(@target_path)
|
99
45
|
end
|
100
46
|
end
|
101
47
|
end
|
data/method_tracer.gemspec
CHANGED
metadata
CHANGED
@@ -1,29 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: method_call_tracer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eddie Lebow
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-09-
|
11
|
+
date: 2018-09-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: where_is
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0'
|
20
|
-
type: :
|
20
|
+
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: minitest
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '5'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '5'
|
27
41
|
description: This tool wraps every specified method with some logging statements that
|
28
42
|
record the call stack, allowing you to see exactly which lines in your application
|
29
43
|
make calls to methods in question. The specified methods can constitute all methods
|