tapping_device 0.4.6 → 0.4.7
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/.github/workflows/ruby.yml +11 -2
- data/Gemfile.lock +9 -1
- data/README.md +134 -98
- data/lib/tapping_device.rb +30 -6
- data/lib/tapping_device/payload.rb +1 -0
- data/lib/tapping_device/sql_tapping_methods.rb +4 -3
- data/lib/tapping_device/version.rb +1 -1
- data/tapping_device.gemspec +1 -0
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 72cee52830dca423c383eb154be4d7352b187cd2bcd848af5ed8d38af0f5ad40
|
4
|
+
data.tar.gz: 96d64f49adfd1de6b3174c9ecdb38d0f8d7e6f03bc0b1b85a79bf3b86613e349
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a6675be23b1bbd4e0dfd6b1c4ea0ccbd39fba970af38a567928066935ab85a20003ecaf157f09f8e20223f2ec0717a72403261541d1b6836c393832c7240d35e
|
7
|
+
data.tar.gz: b93a1bd72210aa7f528687da0edaca7e812cb0849d7d0da8578ba8f5551a2134f6014a1f8c3b7989d750a15bdb734db1826d748de42bf4b995e3f7850cec00de
|
data/.github/workflows/ruby.yml
CHANGED
@@ -13,10 +13,12 @@ jobs:
|
|
13
13
|
os: [ubuntu-latest]
|
14
14
|
steps:
|
15
15
|
- uses: actions/checkout@v1
|
16
|
+
|
16
17
|
- name: Set up Ruby ${{ matrix.ruby_version }}
|
17
18
|
uses: actions/setup-ruby@v1
|
18
19
|
with:
|
19
20
|
ruby-version: ${{ matrix.ruby_version }}
|
21
|
+
|
20
22
|
- name: Install sqlite
|
21
23
|
run: |
|
22
24
|
# See https://github.community/t5/GitHub-Actions/ubuntu-latest-Apt-repository-list-issues/td-p/41122/page/2
|
@@ -24,10 +26,17 @@ jobs:
|
|
24
26
|
sudo apt-get update
|
25
27
|
sudo apt-get install libsqlite3-dev
|
26
28
|
|
27
|
-
- name: Build
|
29
|
+
- name: Build with Rails ${{ matrix.rails_version }}
|
28
30
|
env:
|
29
31
|
RAILS_VERSION: ${{ matrix.rails_version }}
|
30
32
|
run: |
|
31
33
|
gem install bundler
|
32
34
|
bundle install --jobs 4 --retry 3
|
33
|
-
|
35
|
+
|
36
|
+
- name: Run test with Rails ${{ matrix.rails_version }} and publish result
|
37
|
+
uses: paambaati/codeclimate-action@v2.3.0
|
38
|
+
env:
|
39
|
+
CC_TEST_REPORTER_ID: ${{secrets.CC_TEST_REPORTER_ID}}
|
40
|
+
with:
|
41
|
+
coverageCommand: bundle exec rake
|
42
|
+
debug: true
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
tapping_device (0.4.
|
4
|
+
tapping_device (0.4.7)
|
5
5
|
activerecord (>= 5.2)
|
6
6
|
|
7
7
|
GEM
|
@@ -22,8 +22,10 @@ GEM
|
|
22
22
|
concurrent-ruby (1.1.5)
|
23
23
|
database_cleaner (1.7.0)
|
24
24
|
diff-lcs (1.3)
|
25
|
+
docile (1.3.2)
|
25
26
|
i18n (1.7.0)
|
26
27
|
concurrent-ruby (~> 1.0)
|
28
|
+
json (2.3.0)
|
27
29
|
method_source (0.9.2)
|
28
30
|
minitest (5.13.0)
|
29
31
|
pry (0.12.2)
|
@@ -43,6 +45,11 @@ GEM
|
|
43
45
|
diff-lcs (>= 1.2.0, < 2.0)
|
44
46
|
rspec-support (~> 3.8.0)
|
45
47
|
rspec-support (3.8.2)
|
48
|
+
simplecov (0.17.1)
|
49
|
+
docile (~> 1.1)
|
50
|
+
json (>= 1.8, < 3)
|
51
|
+
simplecov-html (~> 0.10.0)
|
52
|
+
simplecov-html (0.10.2)
|
46
53
|
sqlite3 (1.4.1)
|
47
54
|
thread_safe (0.3.6)
|
48
55
|
tzinfo (1.2.6)
|
@@ -58,6 +65,7 @@ DEPENDENCIES
|
|
58
65
|
pry
|
59
66
|
rake (~> 10.0)
|
60
67
|
rspec (~> 3.0)
|
68
|
+
simplecov (= 0.17.1)
|
61
69
|
sqlite3 (>= 1.3.6)
|
62
70
|
tapping_device!
|
63
71
|
|
data/README.md
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
# TappingDevice
|
2
2
|
|
3
3
|

|
4
|
+
[](https://codeclimate.com/github/st0012/tapping_device/maintainability)
|
5
|
+
[](https://codeclimate.com/github/st0012/tapping_device/test_coverage)
|
6
|
+
[](https://www.codetriage.com/st0012/tapping_device)
|
4
7
|
|
5
8
|
## Related Posts
|
6
9
|
- [Debug Rails issues effectively with tapping_device](https://dev.to/st0012/debug-rails-issues-effectively-with-tappingdevice-c7c)
|
@@ -12,14 +15,18 @@
|
|
12
15
|
- [Track Association Calls](#track-association-calls)
|
13
16
|
- [Track Calls that Generates SQL Queries](#track-calls-that-generates-sql-queries)
|
14
17
|
- [Installation](#installation)
|
15
|
-
- [Usages](#
|
16
|
-
-
|
17
|
-
|
18
|
+
- [Usages](#usages)
|
19
|
+
- Tapping Methods
|
20
|
+
- [tap_init!](#tap_init)
|
21
|
+
- [tap_on!](#tap_on)
|
22
|
+
- [tap_passed!](#tap_passed)
|
23
|
+
- [tap_assoc!](#tap_assoc)
|
24
|
+
- [tap_sql!](#tap_sql)
|
18
25
|
- [Options](#options)
|
26
|
+
- [Payload](#payload-of-the-call)
|
19
27
|
- [Advance Usages](#advance-usages)
|
20
28
|
|
21
29
|
## Introduction
|
22
|
-
|
23
30
|
`tapping_device` is a gem built on top of Ruby’s `TracePoint` class that allows you to tap method calls of specified objects. The purpose for this gem is to make debugging Rails applications easier. Here are some sample usages:
|
24
31
|
|
25
32
|
### Track Method Calls
|
@@ -43,7 +50,6 @@ user_id FROM /PROJECT_PATH/sample/app/views/posts/show.html.erb:10
|
|
43
50
|
to_param FROM /RUBY_PATH/gems/2.6.0/gems/actionpack-5.2.0/lib/action_dispatch/routing/route_set.rb:236
|
44
51
|
```
|
45
52
|
|
46
|
-
|
47
53
|
### Track Association Calls
|
48
54
|
|
49
55
|
Or you can use `tap_assoc!`. This is very useful for tracking potential n+1 query calls, here’s a sample from my work
|
@@ -60,7 +66,6 @@ amending_orders FROM /MY_PROJECT/app/models/order.rb:385
|
|
60
66
|
amends_order FROM /MY_PROJECT/app/models/order.rb:432
|
61
67
|
```
|
62
68
|
|
63
|
-
|
64
69
|
### Track Calls that Generates SQL Queries
|
65
70
|
|
66
71
|
`tap_sql!` method helps you track which method calls generate sql queries. This is particularly helpful when tracking calls created from a reused `ActiveRecord::Relation` object.
|
@@ -98,11 +103,9 @@ Method: each generated sql: SELECT "posts".* FROM "posts" from /PROJECT_PATH/rai
|
|
98
103
|
Method: count generated sql: SELECT COUNT(*) FROM "posts" WHERE "posts"."user_id" = ? from /PROJECT_PATH/rails-6-sample/app/views/posts/index.html.erb:31
|
99
104
|
```
|
100
105
|
|
101
|
-
|
102
106
|
However, depending on the size of your application, tapping any object could **harm the performance significantly**. **Don’t use this on production**
|
103
107
|
|
104
108
|
## Installation
|
105
|
-
|
106
109
|
Add this line to your application’s Gemfile:
|
107
110
|
|
108
111
|
```ruby
|
@@ -121,93 +124,12 @@ Or install it yourself as:
|
|
121
124
|
$ gem install tapping_device
|
122
125
|
```
|
123
126
|
|
124
|
-
##
|
125
|
-
In order to use `tapping_device`, you need to include `TappingDevice::Trackable` module in where you want to track your code.
|
126
|
-
|
127
|
-
### Methods
|
128
|
-
- `tap_init!(class)` - tracks a class’ instance initialization
|
129
|
-
- `tap_on!(object)` - tracks any calls received by the object
|
130
|
-
- `tap_assoc!(activerecord_object)` - tracks association calls on a record, like `post.comments`
|
131
|
-
- `tap_sql!(activerecord_relation_or_model)` - tracks sql queries generated from the target
|
132
|
-
|
133
|
-
### Payload of the call
|
134
|
-
All tapping methods (start with `tap_`) takes a block and yield a `Payload` object as block argument. It responds to
|
135
|
-
|
136
|
-
- `target` - the target for `tap_x` call
|
137
|
-
- `receiver` - the receiver object
|
138
|
-
- `method_name` - method’s name (symbol)
|
139
|
-
- e.g. `:name`
|
140
|
-
- `method_object` - the method object that’s being called. It might be `nil` in some edge cases.
|
141
|
-
- `arguments` - arguments of the method call
|
142
|
-
- e.g. `{name: “Stan”, age: 25}`
|
143
|
-
- `return_value` - return value of the method call
|
144
|
-
- `filepath` - path to the file that performs the method call
|
145
|
-
- `line_number`
|
146
|
-
- `defined_class` - in which class that defines the method being called
|
147
|
-
- `trace` - stack trace of the call. Default is an empty array unless `with_trace_to` option is set
|
148
|
-
- `tp` - trace point object of this call
|
149
|
-
|
150
|
-
|
151
|
-
#### Symbols for helpers
|
152
|
-
- `FROM` for method call’s location
|
153
|
-
- `<=` for arguments
|
154
|
-
- `=>` for return value
|
155
|
-
- `@` for defined class
|
156
|
-
|
157
|
-
#### Helpers
|
158
|
-
- `method_name_and_location` - `initialize FROM /PROJECT_PATH/tapping_device/spec/payload_spec.rb:7`
|
159
|
-
- `method_name_and_arguments` - `initialize <= {:name=>\"Stan\", :age=>25}`
|
160
|
-
- `method_name_and_return_value` - `ten => 10`
|
161
|
-
- `method_name_and_defined_class` - `initialize @ Student`
|
162
|
-
- `passed_at` -
|
163
|
-
```
|
164
|
-
Passed as 'object' in method ':initialize'
|
165
|
-
at /Users/st0012/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/actionview-6.0.0/lib/action_view/helpers/tags/label.rb:60
|
166
|
-
```
|
167
|
-
|
168
|
-
You can also set `passed_at(with_method_head: true)` to see the method’s head
|
127
|
+
## Usages
|
128
|
+
In order to use `tapping_device`, you need to include `TappingDevice::Trackable` module in where you want to track your code and call the following helpers.
|
169
129
|
|
170
|
-
|
171
|
-
Passed as 'object' in method ':initialize'
|
172
|
-
> def initialize(template_object, object_name, method_name, object, tag_value)
|
173
|
-
at /Users/st0012/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/actionview-6.0.0/lib/action_view/helpers/tags/label.rb:60
|
174
|
-
```
|
130
|
+
### tap_init!
|
175
131
|
|
176
|
-
|
177
|
-
|
178
|
-
```
|
179
|
-
initialize @ Student
|
180
|
-
<= {:name=>"Stan", :age=>25}
|
181
|
-
=> 25
|
182
|
-
FROM /Users/st0012/projects/tapping_device/spec/payload_spec.rb:7
|
183
|
-
```
|
184
|
-
|
185
|
-
|
186
|
-
### Options
|
187
|
-
- `with_trace_to: 10` - the number of traces we want to put into `trace`. Default is `nil`, so `trace` would be empty
|
188
|
-
- `exclude_by_paths: [/path/]` - an array of call path patterns that we want to skip. This could be very helpful when working on large project like Rails applications.
|
189
|
-
- `filter_by_paths: [/path/]` - only contain calls from the specified paths
|
190
|
-
|
191
|
-
```ruby
|
192
|
-
tap_on!(@post, exclude_by_paths: [/active_record/]).and_print(:method_name_and_location)
|
193
|
-
```
|
194
|
-
|
195
|
-
```
|
196
|
-
_read_attribute FROM /RUBY_PATH/gems/2.6.0/gems/activerecord-5.2.0/lib/active_record/attribute_methods/read.rb:40
|
197
|
-
name FROM /PROJECT_PATH/sample/app/views/posts/show.html.erb:5
|
198
|
-
_read_attribute FROM /RUBY_PATH/gems/2.6.0/gems/activerecord-5.2.0/lib/active_record/attribute_methods/read.rb:40
|
199
|
-
user_id FROM /PROJECT_PATH/sample/app/views/posts/show.html.erb:10
|
200
|
-
.......
|
201
|
-
|
202
|
-
# versus
|
203
|
-
|
204
|
-
name FROM /PROJECT_PATH/sample/app/views/posts/show.html.erb:5
|
205
|
-
user_id FROM /PROJECT_PATH/sample/app/views/posts/show.html.erb:10
|
206
|
-
to_param FROM /RUBY_PATH/gems/2.6.0/gems/actionpack-5.2.0/lib/action_dispatch/routing/route_set.rb:236
|
207
|
-
```
|
208
|
-
|
209
|
-
|
210
|
-
### `#tap_init!`
|
132
|
+
`tap_init!(class)` - tracks a class’ instance initialization
|
211
133
|
|
212
134
|
```ruby
|
213
135
|
calls = []
|
@@ -221,7 +143,9 @@ Student.new("Jane", 23)
|
|
221
143
|
puts(calls.to_s) #=> [[:initialize, {:name=>"Stan", :age=>18}], [:initialize, {:name=>"Jane", :age=>23}]]
|
222
144
|
```
|
223
145
|
|
224
|
-
###
|
146
|
+
### tap_on!
|
147
|
+
|
148
|
+
`tap_on!(object)` - tracks any calls received by the object
|
225
149
|
|
226
150
|
```ruby
|
227
151
|
class PostsController < ApplicationController
|
@@ -243,9 +167,11 @@ user_id FROM /PROJECT_PATH/sample/app/views/posts/show.html.erb:10
|
|
243
167
|
to_param FROM /RUBY_PATH/gems/2.6.0/gems/actionpack-5.2.0/lib/action_dispatch/routing/route_set.rb:236
|
244
168
|
```
|
245
169
|
|
246
|
-
|
170
|
+
Also check the `track_as_records` option if you want to track `ActiveRecord` records.
|
171
|
+
|
172
|
+
### tap_passed!
|
247
173
|
|
248
|
-
This is particularly useful when debugging libraries. It saves your time from jumping between files and check which path the object will go.
|
174
|
+
`tap_passed!(target)` tracks method calls that **takes the target as its argument**. This is particularly useful when debugging libraries. It saves your time from jumping between files and check which path the object will go.
|
249
175
|
|
250
176
|
```ruby
|
251
177
|
class PostsController < ApplicationController
|
@@ -276,7 +202,9 @@ Passed as 'record_or_hash_or_array' in method ':polymorphic_method'
|
|
276
202
|
at /Users/st0012/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/actionpack-6.0.0/lib/action_dispatch/routing/polymorphic_routes.rb:139
|
277
203
|
```
|
278
204
|
|
279
|
-
###
|
205
|
+
### tap_assoc!
|
206
|
+
|
207
|
+
`tap_assoc!(activerecord_object)` tracks association calls on a record, like `post.comments`
|
280
208
|
|
281
209
|
```ruby
|
282
210
|
tap_assoc!(order).and_print(:method_name_and_location)
|
@@ -290,7 +218,9 @@ amending_orders FROM /MY_PROJECT/app/models/order.rb:385
|
|
290
218
|
amends_order FROM /MY_PROJECT/app/models/order.rb:432
|
291
219
|
```
|
292
220
|
|
293
|
-
###
|
221
|
+
### tap_sql!
|
222
|
+
|
223
|
+
`tap_sql!(anything_that_generates_sql_queries)` tracks sql queries generated from the target
|
294
224
|
|
295
225
|
```ruby
|
296
226
|
class PostsController < ApplicationController
|
@@ -324,6 +254,112 @@ Method: count generated sql: SELECT COUNT(*) FROM "posts" WHERE "posts"."user_id
|
|
324
254
|
```
|
325
255
|
|
326
256
|
|
257
|
+
### Options
|
258
|
+
#### with_trace_to
|
259
|
+
It takes an integer as the number of traces we want to put into `trace`. Default is `nil`, so `trace` would be empty.
|
260
|
+
|
261
|
+
```ruby
|
262
|
+
stan = Student.new("Stan", 18)
|
263
|
+
tap_on!(stan, with_trace_to: 5)
|
264
|
+
|
265
|
+
stan.name
|
266
|
+
|
267
|
+
puts(device.calls.first.trace) #=>
|
268
|
+
/Users/st0012/projects/tapping_device/spec/tapping_device_spec.rb:287:in `block (4 levels) in <top (required)>'
|
269
|
+
/Users/st0012/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-core-3.8.2/lib/rspec/core/example.rb:257:in `instance_exec'
|
270
|
+
/Users/st0012/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-core-3.8.2/lib/rspec/core/example.rb:257:in `block in run'
|
271
|
+
/Users/st0012/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-core-3.8.2/lib/rspec/core/example.rb:503:in `block in with_around_and_singleton_context_hooks'
|
272
|
+
/Users/st0012/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-core-3.8.2/lib/rspec/core/example.rb:460:in `block in with_around_example_hooks'
|
273
|
+
/Users/st0012/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-core-3.8.2/lib/rspec/core/hooks.rb:464:in `block in run'
|
274
|
+
```
|
275
|
+
|
276
|
+
#### track_as_records
|
277
|
+
It makes the device to track objects as they are ActiveRecord instances. For example:
|
278
|
+
|
279
|
+
```ruby
|
280
|
+
tap_on!(@post, track_as_records: true)
|
281
|
+
post = Post.find(@post.id) # same record but a different object
|
282
|
+
post.title #=> this call will be recorded as well
|
283
|
+
```
|
284
|
+
|
285
|
+
#### exclude_by_paths
|
286
|
+
It takes an array of call path patterns that we want to skip. This could be very helpful when working on large project like Rails applications.
|
287
|
+
|
288
|
+
```ruby
|
289
|
+
tap_on!(@post, exclude_by_paths: [/active_record/]).and_print(:method_name_and_location)
|
290
|
+
```
|
291
|
+
|
292
|
+
```
|
293
|
+
_read_attribute FROM /RUBY_PATH/gems/2.6.0/gems/activerecord-5.2.0/lib/active_record/attribute_methods/read.rb:40
|
294
|
+
name FROM /PROJECT_PATH/sample/app/views/posts/show.html.erb:5
|
295
|
+
_read_attribute FROM /RUBY_PATH/gems/2.6.0/gems/activerecord-5.2.0/lib/active_record/attribute_methods/read.rb:40
|
296
|
+
user_id FROM /PROJECT_PATH/sample/app/views/posts/show.html.erb:10
|
297
|
+
.......
|
298
|
+
|
299
|
+
# versus
|
300
|
+
|
301
|
+
name FROM /PROJECT_PATH/sample/app/views/posts/show.html.erb:5
|
302
|
+
user_id FROM /PROJECT_PATH/sample/app/views/posts/show.html.erb:10
|
303
|
+
to_param FROM /RUBY_PATH/gems/2.6.0/gems/actionpack-5.2.0/lib/action_dispatch/routing/route_set.rb:236
|
304
|
+
```
|
305
|
+
|
306
|
+
#### filter_by_paths
|
307
|
+
|
308
|
+
Like `exclude_by_paths`, but work in an opposite way.
|
309
|
+
|
310
|
+
|
311
|
+
### Payload of The Call
|
312
|
+
All tapping methods (start with `tap_`) takes a block and yield a `Payload` object as block argument. It responds to
|
313
|
+
|
314
|
+
- `target` - the target for `tap_x` call
|
315
|
+
- `receiver` - the receiver object
|
316
|
+
- `method_name` - method’s name (symbol)
|
317
|
+
- e.g. `:name`
|
318
|
+
- `method_object` - the method object that’s being called. It might be `nil` in some edge cases.
|
319
|
+
- `arguments` - arguments of the method call
|
320
|
+
- e.g. `{name: “Stan”, age: 25}`
|
321
|
+
- `return_value` - return value of the method call
|
322
|
+
- `filepath` - path to the file that performs the method call
|
323
|
+
- `line_number`
|
324
|
+
- `defined_class` - in which class that defines the method being called
|
325
|
+
- `trace` - stack trace of the call. Default is an empty array unless `with_trace_to` option is set
|
326
|
+
- `sql` - sql that generated from the call (only present in `tap_sql!` payloads)
|
327
|
+
- `tp` - trace point object of this call
|
328
|
+
|
329
|
+
|
330
|
+
#### Symbols for Payload Helpers
|
331
|
+
- `FROM` for method call’s location
|
332
|
+
- `<=` for arguments
|
333
|
+
- `=>` for return value
|
334
|
+
- `@` for defined class
|
335
|
+
|
336
|
+
#### Payload Helpers
|
337
|
+
- `method_name_and_location` - `initialize FROM /PROJECT_PATH/tapping_device/spec/payload_spec.rb:7`
|
338
|
+
- `method_name_and_arguments` - `initialize <= {:name=>\"Stan\", :age=>25}`
|
339
|
+
- `method_name_and_return_value` - `ten => 10`
|
340
|
+
- `method_name_and_defined_class` - `initialize @ Student`
|
341
|
+
- `passed_at` -
|
342
|
+
```
|
343
|
+
Passed as 'object' in method ':initialize'
|
344
|
+
at /Users/st0012/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/actionview-6.0.0/lib/action_view/helpers/tags/label.rb:60
|
345
|
+
```
|
346
|
+
|
347
|
+
You can also set `passed_at(with_method_head: true)` to see the method’s head
|
348
|
+
|
349
|
+
```
|
350
|
+
Passed as 'object' in method ':initialize'
|
351
|
+
> def initialize(template_object, object_name, method_name, object, tag_value)
|
352
|
+
at /Users/st0012/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/actionview-6.0.0/lib/action_view/helpers/tags/label.rb:60
|
353
|
+
```
|
354
|
+
|
355
|
+
- `detail_call_info`
|
356
|
+
|
357
|
+
```
|
358
|
+
initialize @ Student
|
359
|
+
<= {:name=>"Stan", :age=>25}
|
360
|
+
=> 25
|
361
|
+
FROM /Users/st0012/projects/tapping_device/spec/payload_spec.rb:7
|
362
|
+
```
|
327
363
|
|
328
364
|
### Advance Usages
|
329
365
|
|
data/lib/tapping_device.rb
CHANGED
@@ -103,11 +103,24 @@ class TappingDevice
|
|
103
103
|
end
|
104
104
|
|
105
105
|
def get_call_location(tp, padding: 0)
|
106
|
+
caller(get_trace_index(tp) + padding).first.split(":")[0..1]
|
107
|
+
end
|
108
|
+
|
109
|
+
def get_trace_index(tp)
|
106
110
|
if tp.event == :c_call
|
107
|
-
|
111
|
+
C_CALLER_START_POINT
|
112
|
+
else
|
113
|
+
CALLER_START_POINT
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def get_traces(tp)
|
118
|
+
if with_trace_to = options[:with_trace_to]
|
119
|
+
trace_index = get_trace_index(tp)
|
120
|
+
caller[trace_index..(trace_index + with_trace_to)]
|
108
121
|
else
|
109
|
-
|
110
|
-
end
|
122
|
+
[]
|
123
|
+
end
|
111
124
|
end
|
112
125
|
|
113
126
|
# this needs to be placed upfront so we can exclude noise before doing more work
|
@@ -130,7 +143,7 @@ class TappingDevice
|
|
130
143
|
filepath: filepath,
|
131
144
|
line_number: line_number,
|
132
145
|
defined_class: tp.defined_class,
|
133
|
-
trace:
|
146
|
+
trace: get_traces(tp),
|
134
147
|
tp: tp
|
135
148
|
})
|
136
149
|
end
|
@@ -159,8 +172,9 @@ class TappingDevice
|
|
159
172
|
end
|
160
173
|
|
161
174
|
def tap_passed?(object, tp)
|
162
|
-
# we don't care about calls from the device instance
|
175
|
+
# we don't care about calls from the device instance or helper methods
|
163
176
|
return false if is_from_target?(self, tp)
|
177
|
+
return false if tp.defined_class == TappingDevice::Trackable || tp.defined_class == TappingDevice
|
164
178
|
|
165
179
|
method_object = get_method_object_from(tp.self, tp.callee_id)
|
166
180
|
return false unless method_object.is_a?(Method)
|
@@ -196,6 +210,7 @@ class TappingDevice
|
|
196
210
|
options[:with_trace_to] ||= 50
|
197
211
|
options[:root_device] ||= self
|
198
212
|
options[:descendants] ||= []
|
213
|
+
options[:track_as_records] ||= false
|
199
214
|
options
|
200
215
|
end
|
201
216
|
|
@@ -207,7 +222,16 @@ class TappingDevice
|
|
207
222
|
end
|
208
223
|
|
209
224
|
def is_from_target?(object, tp)
|
210
|
-
|
225
|
+
comparsion = tp.self
|
226
|
+
is_the_same_record?(object, comparsion) || object.__id__ == comparsion.__id__
|
227
|
+
end
|
228
|
+
|
229
|
+
def is_the_same_record?(target, comparsion)
|
230
|
+
return false unless options[:track_as_records]
|
231
|
+
if target.is_a?(ActiveRecord::Base) && comparsion.is_a?(target.class)
|
232
|
+
primary_key = target.class.primary_key
|
233
|
+
target.send(primary_key) && target.send(primary_key) == comparsion.send(primary_key)
|
234
|
+
end
|
211
235
|
end
|
212
236
|
|
213
237
|
def record_call!(payload)
|
@@ -18,7 +18,7 @@ class TappingDevice
|
|
18
18
|
########## Check if the call is worth recording ##########
|
19
19
|
filepath, line_number = get_call_location(start_tp, padding: 1) # we need extra padding because of `with_trace_point_on_target`
|
20
20
|
method = start_tp.callee_id
|
21
|
-
next if
|
21
|
+
next if already_recording?(method)
|
22
22
|
|
23
23
|
########## Start the recording ##########
|
24
24
|
# 1. Mark recording state by pushing method into @call_stack
|
@@ -62,8 +62,9 @@ class TappingDevice
|
|
62
62
|
device = TappingDevice.new do |sql_listener_payload|
|
63
63
|
values = sql_listener_payload.arguments[:values]
|
64
64
|
|
65
|
-
next if
|
66
|
-
|
65
|
+
next if should_be_skipped_by_paths?(payload.filepath) ||
|
66
|
+
["SCHEMA", "TRANSACTION"].include?(values[:name]) ||
|
67
|
+
values[:sql].match?(/SAVEPOINT/)
|
67
68
|
|
68
69
|
payload[:sql] = values[:sql]
|
69
70
|
record_call!(payload)
|
data/tapping_device.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tapping_device
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- st0012
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-12-
|
11
|
+
date: 2019-12-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -108,6 +108,20 @@ dependencies:
|
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '3.0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: simplecov
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - '='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 0.17.1
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - '='
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 0.17.1
|
111
125
|
description: tapping_device provides useful helpers to intercept method calls
|
112
126
|
email:
|
113
127
|
- stan001212@gmail.com
|