appmap 0.45.1 → 0.48.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.
- checksums.yaml +4 -4
- data/.dockerignore +0 -1
- data/.travis.yml +10 -0
- data/CHANGELOG.md +37 -0
- data/README.md +10 -27
- data/lib/appmap.rb +1 -2
- data/lib/appmap/class_map.rb +7 -15
- data/lib/appmap/config.rb +96 -34
- data/lib/appmap/event.rb +30 -29
- data/lib/appmap/handler/function.rb +1 -1
- data/lib/appmap/handler/rails/request_handler.rb +124 -0
- data/lib/appmap/handler/rails/sql_handler.rb +152 -0
- data/lib/appmap/handler/rails/template.rb +155 -0
- data/lib/appmap/hook.rb +3 -1
- data/lib/appmap/hook/method.rb +1 -1
- data/lib/appmap/minitest.rb +1 -1
- data/lib/appmap/railtie.rb +6 -28
- data/lib/appmap/rspec.rb +1 -1
- data/lib/appmap/trace.rb +46 -6
- data/lib/appmap/util.rb +13 -1
- data/lib/appmap/version.rb +2 -2
- data/package-lock.json +3 -3
- data/spec/abstract_controller_base_spec.rb +67 -8
- data/spec/class_map_spec.rb +3 -3
- data/spec/fixtures/hook/exception_method.rb +6 -0
- data/spec/fixtures/rails5_users_app/config/application.rb +0 -2
- data/spec/fixtures/rails6_users_app/config/application.rb +0 -2
- data/spec/hook_spec.rb +37 -56
- data/spec/railtie_spec.rb +7 -11
- data/spec/util_spec.rb +18 -1
- data/test/bundle_vendor_test.rb +35 -0
- data/test/fixtures/bundle_vendor_app/Gemfile +8 -0
- data/test/fixtures/bundle_vendor_app/appmap.yml +4 -0
- data/test/fixtures/bundle_vendor_app/cli.rb +54 -0
- data/test/gem_test.rb +1 -1
- metadata +9 -4
- data/lib/appmap/rails/request_handler.rb +0 -122
- data/lib/appmap/rails/sql_handler.rb +0 -150
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 698da91c88a89867584e3d78e10974a4a2f8d726636d60366c214be9e3ddbf97
|
4
|
+
data.tar.gz: eee0b62c442eecc5cf978960128c0b19ff2ebdc393770d8cefc820c82a451d4f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 77ae4b055912a7bd6f62f32bb2db7d3684d614453fb82bb7d8f53496181919609ca2af0a65906ca36f1f28aaf28e06c64d6f5e6326b8f384f4c1206c22af559a
|
7
|
+
data.tar.gz: a72831c1908beb0130b4797ea5455b976677caec810edcdf0009b9be609ba6510a59873b66ca4df5406fe8f3e5aea995d8dabc983573517adc67fdf86cad822a
|
data/.dockerignore
CHANGED
data/.travis.yml
CHANGED
@@ -17,6 +17,16 @@ before_script:
|
|
17
17
|
cache:
|
18
18
|
bundler: true
|
19
19
|
|
20
|
+
before_install:
|
21
|
+
# see https://blog.travis-ci.com/docker-rate-limits
|
22
|
+
# and also https://www.docker.com/blog/what-you-need-to-know-about-upcoming-docker-hub-rate-limiting/
|
23
|
+
# if we do not use authorized account,
|
24
|
+
# the pulls-per-IP quota is shared with other Travis users
|
25
|
+
- >
|
26
|
+
if [ ! -z "$DOCKERHUB_PASSWORD" ] && [ ! -z "$DOCKERHUB_USERNAME" ]; then
|
27
|
+
echo "$DOCKERHUB_PASSWORD" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin ;
|
28
|
+
fi
|
29
|
+
|
20
30
|
|
21
31
|
# GEM_ALTERNATIVE_NAME only needed for deployment
|
22
32
|
jobs:
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,40 @@
|
|
1
|
+
## [0.48.1](https://github.com/applandinc/appmap-ruby/compare/v0.48.0...v0.48.1) (2021-05-25)
|
2
|
+
|
3
|
+
|
4
|
+
### Bug Fixes
|
5
|
+
|
6
|
+
* Account for bundle path when normalizing source path ([095c278](https://github.com/applandinc/appmap-ruby/commit/095c27818fc8ae8dfa39b30516d37c6dfd642d9c))
|
7
|
+
* Scan exception messages for non-UTF8 characters ([3dcaeae](https://github.com/applandinc/appmap-ruby/commit/3dcaeae44da5e40e432eda41caf5b9ebff5bea12))
|
8
|
+
|
9
|
+
# [0.48.0](https://github.com/applandinc/appmap-ruby/compare/v0.47.1...v0.48.0) (2021-05-19)
|
10
|
+
|
11
|
+
|
12
|
+
### Features
|
13
|
+
|
14
|
+
* Hook the code only when APPMAP=true ([dd9e383](https://github.com/applandinc/appmap-ruby/commit/dd9e383024d1d9205a617d46bd64b90820035533))
|
15
|
+
* Remove server process recording from doc and tests ([383ba0a](https://github.com/applandinc/appmap-ruby/commit/383ba0ad444922a0a85409477d11bc7ed06a9160))
|
16
|
+
|
17
|
+
## [0.47.1](https://github.com/applandinc/appmap-ruby/compare/v0.47.0...v0.47.1) (2021-05-13)
|
18
|
+
|
19
|
+
|
20
|
+
### Bug Fixes
|
21
|
+
|
22
|
+
* Add the proper template function hooks for Rails 6.0.7 ([175f489](https://github.com/applandinc/appmap-ruby/commit/175f489acbaed77ad52a18d805e4b6eeae1abfdb))
|
23
|
+
|
24
|
+
# [0.47.0](https://github.com/applandinc/appmap-ruby/compare/v0.46.0...v0.47.0) (2021-05-13)
|
25
|
+
|
26
|
+
|
27
|
+
### Features
|
28
|
+
|
29
|
+
* Emit swagger-style normalized paths instead of Rails-style ones ([5a93cd7](https://github.com/applandinc/appmap-ruby/commit/5a93cd7096ca195146a84a6733c7d502dbcd0272))
|
30
|
+
|
31
|
+
# [0.46.0](https://github.com/applandinc/appmap-ruby/compare/v0.45.1...v0.46.0) (2021-05-12)
|
32
|
+
|
33
|
+
|
34
|
+
### Features
|
35
|
+
|
36
|
+
* Record view template rendering events and template paths ([973b258](https://github.com/applandinc/appmap-ruby/commit/973b2581b6e2d4e15a1b93331e4e95a88678faae))
|
37
|
+
|
1
38
|
## [0.45.1](https://github.com/applandinc/appmap-ruby/compare/v0.45.0...v0.45.1) (2021-05-04)
|
2
39
|
|
3
40
|
|
data/README.md
CHANGED
@@ -9,7 +9,6 @@
|
|
9
9
|
- [Minitest](#minitest)
|
10
10
|
- [Cucumber](#cucumber)
|
11
11
|
- [Remote recording](#remote-recording)
|
12
|
-
- [Server process recording](#server-process-recording)
|
13
12
|
- [AppMap for VSCode](#appmap-for-vscode)
|
14
13
|
- [AppMap Swagger](#appmap-swagger)
|
15
14
|
- [Uploading AppMaps](#uploading-appmaps)
|
@@ -84,22 +83,6 @@ If you are using Ruby on Rails, require the railtie after Rails is loaded.
|
|
84
83
|
require 'appmap/railtie' if defined?(AppMap).
|
85
84
|
```
|
86
85
|
|
87
|
-
**application.rb**
|
88
|
-
|
89
|
-
Add this line to *application.rb*, to enable server recording with `APPMAP_RECORD=true`:
|
90
|
-
|
91
|
-
```ruby
|
92
|
-
module MyApp
|
93
|
-
class Application < Rails::Application
|
94
|
-
...
|
95
|
-
|
96
|
-
config.appmap.enabled = true if ENV['APPMAP_RECORD']
|
97
|
-
|
98
|
-
...
|
99
|
-
end
|
100
|
-
end
|
101
|
-
```
|
102
|
-
|
103
86
|
# Configuration
|
104
87
|
|
105
88
|
When you run your program, the `appmap` gem reads configuration settings from `appmap.yml`. Here's a sample configuration
|
@@ -326,25 +309,25 @@ if defined?(AppMap)
|
|
326
309
|
end
|
327
310
|
```
|
328
311
|
|
329
|
-
2. Download and unpack the [AppLand browser extension](https://github.com/applandinc/appland-browser-extension). Install into Chrome using `chrome://extensions/`. Turn on "Developer Mode" and then load the extension using the "Load unpacked" button.
|
312
|
+
2. (optional) Download and unpack the [AppLand browser extension](https://github.com/applandinc/appland-browser-extension). Install into Chrome using `chrome://extensions/`. Turn on "Developer Mode" and then load the extension using the "Load unpacked" button.
|
330
313
|
|
331
|
-
3. Start your Rails application server
|
314
|
+
3. Start your Rails application server, with `APPMAP_RECORD=true`. For example:
|
332
315
|
|
333
316
|
```sh-session
|
334
|
-
$ bundle exec rails server
|
317
|
+
$ APPMAP_RECORD=true bundle exec rails server
|
335
318
|
```
|
336
319
|
|
337
|
-
4.
|
320
|
+
4. Start the recording
|
338
321
|
|
339
|
-
|
322
|
+
Option 1: Open the AppLand browser extension and push `Start`.
|
323
|
+
Option 2: `curl -XPOST localhost:3000/_appmap/record` (be sure and get the port number right)
|
340
324
|
|
341
|
-
|
342
|
-
|
343
|
-
## Server process recording
|
325
|
+
5. Use your app. For example, perform a login flow, or run through a manual UI test.
|
344
326
|
|
345
|
-
|
327
|
+
6. Finish the recording.
|
346
328
|
|
347
|
-
|
329
|
+
Option 1: Open the AppLand browser extension and push `Stop`. The recording will be transferred to the AppLand website and opened in your browser.
|
330
|
+
Option 2: `curl -XDELETE localhost:3000/_appmap/record > recording.appmap.json` - Saves the recording as a local file.
|
348
331
|
|
349
332
|
|
350
333
|
# AppMap for VSCode
|
data/lib/appmap.rb
CHANGED
@@ -9,7 +9,6 @@ end
|
|
9
9
|
|
10
10
|
require 'appmap/version'
|
11
11
|
require 'appmap/hook'
|
12
|
-
require 'appmap/handler/net_http'
|
13
12
|
require 'appmap/config'
|
14
13
|
require 'appmap/trace'
|
15
14
|
require 'appmap/class_map'
|
@@ -99,4 +98,4 @@ module AppMap
|
|
99
98
|
end
|
100
99
|
|
101
100
|
require 'appmap/railtie' if defined?(::Rails::Railtie)
|
102
|
-
AppMap.initialize
|
101
|
+
AppMap.initialize if ENV['APPMAP'] == 'true'
|
data/lib/appmap/class_map.rb
CHANGED
@@ -82,16 +82,13 @@ module AppMap
|
|
82
82
|
protected
|
83
83
|
|
84
84
|
def add_function(root, method)
|
85
|
-
package = method.package
|
86
|
-
static = method.static
|
87
|
-
|
88
85
|
object_infos = [
|
89
86
|
{
|
90
|
-
name: package
|
87
|
+
name: method.package,
|
91
88
|
type: 'package'
|
92
89
|
}
|
93
90
|
]
|
94
|
-
object_infos += method.
|
91
|
+
object_infos += method.class_name.split('::').map do |name|
|
95
92
|
{
|
96
93
|
name: name,
|
97
94
|
type: 'class'
|
@@ -100,7 +97,7 @@ module AppMap
|
|
100
97
|
function_info = {
|
101
98
|
name: method.name,
|
102
99
|
type: 'function',
|
103
|
-
static: static
|
100
|
+
static: method.static
|
104
101
|
}
|
105
102
|
location = method.source_location
|
106
103
|
|
@@ -108,20 +105,15 @@ module AppMap
|
|
108
105
|
if location
|
109
106
|
location_file, lineno = location
|
110
107
|
location_file = location_file[Dir.pwd.length + 1..-1] if location_file.index(Dir.pwd) == 0
|
111
|
-
[ location_file, lineno ].join(':')
|
108
|
+
[ location_file, lineno ].compact.join(':')
|
112
109
|
else
|
113
|
-
[ method.
|
110
|
+
[ method.class_name, method.static ? '.' : '#', method.name ].join
|
114
111
|
end
|
115
112
|
|
116
|
-
comment =
|
117
|
-
method.comment
|
118
|
-
rescue MethodSource::SourceNotFoundError
|
119
|
-
nil
|
120
|
-
end
|
121
|
-
|
113
|
+
comment = method.comment
|
122
114
|
function_info[:comment] = comment unless comment.blank?
|
123
115
|
|
124
|
-
function_info[:labels] = parse_labels(comment) + (
|
116
|
+
function_info[:labels] = parse_labels(comment) + (method.labels || [])
|
125
117
|
object_infos << function_info
|
126
118
|
|
127
119
|
parent = root
|
data/lib/appmap/config.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'appmap/handler/net_http'
|
4
|
+
require 'appmap/handler/rails/template'
|
5
|
+
|
3
6
|
module AppMap
|
4
7
|
class Config
|
5
8
|
# Specifies a code +path+ to be mapped.
|
@@ -82,18 +85,7 @@ module AppMap
|
|
82
85
|
end
|
83
86
|
end
|
84
87
|
|
85
|
-
|
86
|
-
def to_h
|
87
|
-
{
|
88
|
-
package: package,
|
89
|
-
class: cls,
|
90
|
-
labels: labels,
|
91
|
-
functions: function_names.map(&:to_sym)
|
92
|
-
}.compact
|
93
|
-
end
|
94
|
-
end
|
95
|
-
private_constant :Function
|
96
|
-
|
88
|
+
# Identifies specific methods within a package which should be hooked.
|
97
89
|
class TargetMethods # :nodoc:
|
98
90
|
attr_reader :method_names, :package
|
99
91
|
|
@@ -115,24 +107,91 @@ module AppMap
|
|
115
107
|
end
|
116
108
|
private_constant :TargetMethods
|
117
109
|
|
118
|
-
|
110
|
+
# Function represents a specific function configured for hooking by the +functions+
|
111
|
+
# entry in appmap.yml. When the Config is initialized, each Function is converted into
|
112
|
+
# a Package and TargetMethods. It's called a Function rather than a Method, because Function
|
113
|
+
# is the AppMap terminology.
|
114
|
+
Function = Struct.new(:package, :cls, :labels, :function_names) do # :nodoc:
|
115
|
+
def to_h
|
116
|
+
{
|
117
|
+
package: package,
|
118
|
+
class: cls,
|
119
|
+
labels: labels,
|
120
|
+
functions: function_names.map(&:to_sym)
|
121
|
+
}.compact
|
122
|
+
end
|
123
|
+
end
|
124
|
+
private_constant :Function
|
119
125
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
126
|
+
ClassTargetMethods = Struct.new(:cls, :target_methods) # :nodoc:
|
127
|
+
private_constant :ClassTargetMethods
|
128
|
+
|
129
|
+
MethodHook = Struct.new(:cls, :method_names, :labels) # :nodoc:
|
130
|
+
private_constant :MethodHook
|
131
|
+
|
132
|
+
class << self
|
133
|
+
def package_hooks(gem_name, methods, handler_class: nil, package_name: nil)
|
134
|
+
Array(methods).map do |method|
|
135
|
+
package = Package.build_from_gem(gem_name, package_name: package_name, labels: method.labels, shallow: false, optional: true)
|
136
|
+
next unless package
|
137
|
+
|
138
|
+
package.handler_class = handler_class if handler_class
|
139
|
+
ClassTargetMethods.new(method.cls, TargetMethods.new(Array(method.method_names), package))
|
140
|
+
end.compact
|
141
|
+
end
|
142
|
+
|
143
|
+
def method_hook(cls, method_names, labels)
|
144
|
+
MethodHook.new(cls, method_names, labels)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# Hook well-known functions. When a function configured here is available in the bundle, it will be hooked with the
|
149
|
+
# predefined labels specified here. If any of these hooks are not desired, they can be disabled in the +exclude+ section
|
150
|
+
# of appmap.yml.
|
151
|
+
METHOD_HOOKS = [
|
152
|
+
package_hooks('actionview',
|
153
|
+
[
|
154
|
+
method_hook('ActionView::Renderer', :render, %w[mvc.view]),
|
155
|
+
method_hook('ActionView::TemplateRenderer', :render, %w[mvc.view]),
|
156
|
+
method_hook('ActionView::PartialRenderer', :render, %w[mvc.view])
|
157
|
+
],
|
158
|
+
handler_class: AppMap::Handler::Rails::Template::RenderHandler,
|
159
|
+
package_name: 'action_view'
|
160
|
+
),
|
161
|
+
package_hooks('actionview',
|
162
|
+
[
|
163
|
+
method_hook('ActionView::Resolver', %i[find_all find_all_anywhere], %w[mvc.template.resolver])
|
164
|
+
],
|
165
|
+
handler_class: AppMap::Handler::Rails::Template::ResolverHandler,
|
166
|
+
package_name: 'action_view'
|
167
|
+
),
|
168
|
+
package_hooks('actionpack',
|
169
|
+
[
|
170
|
+
method_hook('ActionDispatch::Request::Session', %i[destroy [] dig values []= clear update delete fetch merge], %w[http.session]),
|
171
|
+
method_hook('ActionDispatch::Cookies::CookieJar', %i[[]= clear update delete recycle], %w[http.session]),
|
172
|
+
method_hook('ActionDispatch::Cookies::EncryptedCookieJar', %i[[]= clear update delete recycle], %w[http.cookie crypto.encrypt])
|
173
|
+
],
|
174
|
+
package_name: 'action_dispatch'
|
175
|
+
),
|
176
|
+
package_hooks('cancancan',
|
177
|
+
[
|
178
|
+
method_hook('CanCan::ControllerAdditions', %i[authorize! can? cannot?], %w[security.authorization]),
|
179
|
+
method_hook('CanCan::Ability', %i[authorize?], %w[security.authorization])
|
180
|
+
]
|
181
|
+
),
|
182
|
+
package_hooks('actionpack',
|
183
|
+
[
|
184
|
+
method_hook('ActionController::Instrumentation', %i[process_action send_file send_data redirect_to], %w[mvc.controller])
|
185
|
+
],
|
186
|
+
package_name: 'action_controller'
|
187
|
+
)
|
188
|
+
].flatten.freeze
|
134
189
|
|
135
|
-
|
190
|
+
OPENSSL_PACKAGES = ->(labels) { Package.build_from_path('openssl', package_name: 'openssl', labels: labels) }
|
191
|
+
|
192
|
+
# Hook functions which are builtin to Ruby. Because they are builtins, they may be loaded before appmap.
|
193
|
+
# Therefore, we can't rely on TracePoint to report the loading of this code.
|
194
|
+
BUILTIN_HOOKS = {
|
136
195
|
'OpenSSL::PKey::PKey' => TargetMethods.new(:sign, OPENSSL_PACKAGES.(%w[crypto.pkey])),
|
137
196
|
'OpenSSL::X509::Request' => TargetMethods.new(%i[sign verify], OPENSSL_PACKAGES.(%w[crypto.x509])),
|
138
197
|
'OpenSSL::PKCS5' => TargetMethods.new(%i[pbkdf2_hmac_sha1 pbkdf2_hmac], OPENSSL_PACKAGES.(%w[crypto.pkcs5])),
|
@@ -159,26 +218,29 @@ module AppMap
|
|
159
218
|
'JSON::Ext::Generator::State' => TargetMethods.new(:generate, Package.build_from_path('json', package_name: 'json', labels: %w[format.json])),
|
160
219
|
}.freeze
|
161
220
|
|
162
|
-
attr_reader :name, :packages, :exclude, :hooked_methods, :
|
221
|
+
attr_reader :name, :packages, :exclude, :hooked_methods, :builtin_hooks
|
163
222
|
|
164
223
|
def initialize(name, packages, exclude: [], functions: [])
|
165
224
|
@name = name
|
166
225
|
@packages = packages
|
167
|
-
@hook_paths = packages.map(&:path)
|
226
|
+
@hook_paths = Set.new(packages.map(&:path))
|
168
227
|
@exclude = exclude
|
169
|
-
@
|
228
|
+
@builtin_hooks = BUILTIN_HOOKS
|
170
229
|
@functions = functions
|
171
|
-
|
230
|
+
|
231
|
+
@hooked_methods = METHOD_HOOKS.each_with_object(Hash.new { |h,k| h[k] = [] }) do |cls_target_methods, hooked_methods|
|
232
|
+
hooked_methods[cls_target_methods.cls] << cls_target_methods.target_methods
|
233
|
+
end
|
234
|
+
|
172
235
|
functions.each do |func|
|
173
236
|
package_options = {}
|
174
237
|
package_options[:labels] = func.labels if func.labels
|
175
|
-
@hooked_methods[func.cls] ||= []
|
176
238
|
@hooked_methods[func.cls] << TargetMethods.new(func.function_names, Package.build_from_path(func.package, package_options))
|
177
239
|
end
|
178
240
|
|
179
241
|
@hooked_methods.each_value do |hooks|
|
180
242
|
Array(hooks).each do |hook|
|
181
|
-
@hook_paths << hook.package.path
|
243
|
+
@hook_paths << hook.package.path
|
182
244
|
end
|
183
245
|
end
|
184
246
|
end
|
data/lib/appmap/event.rb
CHANGED
@@ -21,10 +21,10 @@ module AppMap
|
|
21
21
|
LIMIT = 100
|
22
22
|
|
23
23
|
class << self
|
24
|
-
def build_from_invocation(
|
25
|
-
|
26
|
-
|
27
|
-
|
24
|
+
def build_from_invocation(event_type, event:)
|
25
|
+
event.id = AppMap::Event.next_id_counter
|
26
|
+
event.event = event_type
|
27
|
+
event.thread_id = Thread.current.object_id
|
28
28
|
end
|
29
29
|
|
30
30
|
# Gets a display string for a value. This is not meant to be a machine deserializable value.
|
@@ -48,8 +48,6 @@ module AppMap
|
|
48
48
|
nil
|
49
49
|
end
|
50
50
|
|
51
|
-
protected
|
52
|
-
|
53
51
|
# Heuristic for dynamically defined class whose name can be nil
|
54
52
|
def best_class_name(value)
|
55
53
|
value_cls = value.class
|
@@ -103,19 +101,20 @@ module AppMap
|
|
103
101
|
attr_accessor :defined_class, :method_id, :path, :lineno, :parameters, :receiver, :static
|
104
102
|
|
105
103
|
class << self
|
106
|
-
def build_from_invocation(
|
104
|
+
def build_from_invocation(defined_class, method, receiver, arguments, event: MethodCall.new)
|
105
|
+
event ||= MethodCall.new
|
107
106
|
defined_class ||= 'Class'
|
108
|
-
|
107
|
+
event.tap do
|
109
108
|
static = receiver.is_a?(Module)
|
110
|
-
|
111
|
-
|
109
|
+
event.defined_class = defined_class
|
110
|
+
event.method_id = method.name.to_s
|
112
111
|
if method.source_location
|
113
112
|
path = method.source_location[0]
|
114
113
|
path = path[Dir.pwd.length + 1..-1] if path.index(Dir.pwd) == 0
|
115
|
-
|
116
|
-
|
114
|
+
event.path = path
|
115
|
+
event.lineno = method.source_location[1]
|
117
116
|
else
|
118
|
-
|
117
|
+
event.path = [ defined_class, static ? '.' : '#', method.name ].join
|
119
118
|
end
|
120
119
|
|
121
120
|
# Check if the method has key parameters. If there are any they'll always be last.
|
@@ -123,7 +122,7 @@ module AppMap
|
|
123
122
|
has_key = [[:dummy], *method.parameters].last.first.to_s.start_with?('key') && arguments[-1].is_a?(Hash)
|
124
123
|
kwargs = has_key && arguments[-1].dup || {}
|
125
124
|
|
126
|
-
|
125
|
+
event.parameters = method.parameters.map.with_index do |method_param, idx|
|
127
126
|
param_type, param_name = method_param
|
128
127
|
param_name ||= 'arg'
|
129
128
|
value = case param_type
|
@@ -144,13 +143,13 @@ module AppMap
|
|
144
143
|
kind: param_type
|
145
144
|
}
|
146
145
|
end
|
147
|
-
|
146
|
+
event.receiver = {
|
148
147
|
class: best_class_name(receiver),
|
149
148
|
object_id: receiver.__id__,
|
150
149
|
value: display_string(receiver)
|
151
150
|
}
|
152
|
-
|
153
|
-
MethodEvent.build_from_invocation(
|
151
|
+
event.static = static
|
152
|
+
MethodEvent.build_from_invocation(:call, event: event)
|
154
153
|
end
|
155
154
|
end
|
156
155
|
end
|
@@ -175,11 +174,12 @@ module AppMap
|
|
175
174
|
attr_accessor :parent_id, :elapsed
|
176
175
|
|
177
176
|
class << self
|
178
|
-
def build_from_invocation(
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
177
|
+
def build_from_invocation(parent_id, elapsed: nil, event: MethodReturnIgnoreValue.new)
|
178
|
+
event ||= MethodReturnIgnoreValue.new
|
179
|
+
event.tap do |_|
|
180
|
+
event.parent_id = parent_id
|
181
|
+
event.elapsed = elapsed
|
182
|
+
MethodEvent.build_from_invocation(:return, event: event)
|
183
183
|
end
|
184
184
|
end
|
185
185
|
end
|
@@ -187,7 +187,7 @@ module AppMap
|
|
187
187
|
def to_h
|
188
188
|
super.tap do |h|
|
189
189
|
h[:parent_id] = parent_id
|
190
|
-
h[:elapsed] = elapsed
|
190
|
+
h[:elapsed] = elapsed if elapsed
|
191
191
|
end
|
192
192
|
end
|
193
193
|
end
|
@@ -196,10 +196,11 @@ module AppMap
|
|
196
196
|
attr_accessor :return_value, :exceptions
|
197
197
|
|
198
198
|
class << self
|
199
|
-
def build_from_invocation(
|
200
|
-
|
199
|
+
def build_from_invocation(parent_id, return_value, exception, elapsed: nil, event: MethodReturn.new)
|
200
|
+
event ||= MethodReturn.new
|
201
|
+
event.tap do |_|
|
201
202
|
if return_value
|
202
|
-
|
203
|
+
event.return_value = {
|
203
204
|
class: best_class_name(return_value),
|
204
205
|
value: display_string(return_value),
|
205
206
|
object_id: return_value.__id__
|
@@ -212,7 +213,7 @@ module AppMap
|
|
212
213
|
exception_backtrace = next_exception.backtrace_locations.try(:[], 0)
|
213
214
|
exceptions << {
|
214
215
|
class: best_class_name(next_exception),
|
215
|
-
message: next_exception.message,
|
216
|
+
message: display_string(next_exception.message),
|
216
217
|
object_id: next_exception.__id__,
|
217
218
|
path: exception_backtrace&.path,
|
218
219
|
lineno: exception_backtrace&.lineno
|
@@ -220,9 +221,9 @@ module AppMap
|
|
220
221
|
next_exception = next_exception.cause
|
221
222
|
end
|
222
223
|
|
223
|
-
|
224
|
+
event.exceptions = exceptions
|
224
225
|
end
|
225
|
-
MethodReturnIgnoreValue.build_from_invocation(
|
226
|
+
MethodReturnIgnoreValue.build_from_invocation(parent_id, elapsed: elapsed, event: event)
|
226
227
|
end
|
227
228
|
end
|
228
229
|
end
|