appmap 0.41.1 → 0.44.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +17 -2
- data/CHANGELOG.md +31 -0
- data/README.md +54 -22
- data/appmap.gemspec +0 -2
- data/lib/appmap.rb +3 -2
- data/lib/appmap/class_map.rb +7 -10
- data/lib/appmap/config.rb +94 -34
- data/lib/appmap/cucumber.rb +1 -1
- data/lib/appmap/event.rb +18 -0
- data/lib/appmap/hook.rb +42 -22
- data/lib/appmap/hook/method.rb +1 -1
- data/lib/appmap/minitest.rb +35 -30
- data/lib/appmap/rails/request_handler.rb +41 -10
- data/lib/appmap/record.rb +1 -1
- data/lib/appmap/rspec.rb +32 -96
- data/lib/appmap/util.rb +16 -0
- data/lib/appmap/version.rb +1 -1
- data/patch +1447 -0
- data/spec/abstract_controller_base_spec.rb +69 -26
- data/spec/class_map_spec.rb +3 -11
- data/spec/config_spec.rb +31 -1
- data/spec/fixtures/hook/custom_instance_method.rb +11 -0
- data/spec/fixtures/hook/method_named_call.rb +11 -0
- data/spec/fixtures/rails5_users_app/Gemfile +7 -3
- data/spec/fixtures/rails5_users_app/app/controllers/api/users_controller.rb +2 -0
- data/spec/fixtures/rails5_users_app/app/controllers/users_controller.rb +9 -1
- data/spec/fixtures/rails5_users_app/config/application.rb +2 -0
- data/spec/fixtures/rails5_users_app/create_app +8 -2
- data/spec/fixtures/rails5_users_app/docker-compose.yml +3 -0
- data/spec/fixtures/rails5_users_app/spec/controllers/users_controller_api_spec.rb +16 -3
- data/spec/fixtures/rails5_users_app/spec/controllers/users_controller_spec.rb +2 -2
- data/spec/fixtures/rails5_users_app/spec/models/user_spec.rb +2 -12
- data/spec/fixtures/rails5_users_app/spec/rails_helper.rb +3 -9
- data/spec/fixtures/rails6_users_app/Gemfile +5 -4
- data/spec/fixtures/rails6_users_app/app/controllers/api/users_controller.rb +1 -0
- data/spec/fixtures/rails6_users_app/app/controllers/users_controller.rb +9 -1
- data/spec/fixtures/rails6_users_app/config/application.rb +2 -0
- data/spec/fixtures/rails6_users_app/create_app +8 -2
- data/spec/fixtures/rails6_users_app/docker-compose.yml +3 -0
- data/spec/fixtures/rails6_users_app/spec/controllers/users_controller_api_spec.rb +16 -3
- data/spec/fixtures/rails6_users_app/spec/controllers/users_controller_spec.rb +2 -2
- data/spec/fixtures/rails6_users_app/spec/models/user_spec.rb +2 -12
- data/spec/fixtures/rails6_users_app/spec/rails_helper.rb +3 -9
- data/spec/hook_spec.rb +134 -10
- data/spec/record_sql_rails_pg_spec.rb +1 -1
- data/spec/spec_helper.rb +6 -0
- data/test/expectations/openssl_test_key_sign1.json +2 -4
- data/test/fixtures/rspec_recorder/spec/decorated_hello_spec.rb +3 -3
- data/test/fixtures/rspec_recorder/spec/plain_hello_spec.rb +1 -1
- data/test/gem_test.rb +1 -1
- data/test/minitest_test.rb +1 -2
- data/test/rspec_test.rb +1 -20
- metadata +7 -8
- data/exe/appmap +0 -154
- data/spec/rspec_feature_metadata_spec.rb +0 -31
- data/test/cli_test.rb +0 -116
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 02dfa68caaa5e5413c68ae06e89664a676624c9dbb301e2ebbc2a7ae26359afd
|
4
|
+
data.tar.gz: af97e3fb4bb428a238b854ef30969f232c48d4f3a59956865a4cc95788ac35e8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9a0f2454acf5d10c48aaf1abb6e4b23d674acbbfe495770a25ff83093c38dd81cf0bb1c85dfbae4691773586ace8500c3f9b879b31749c4142851f460ed1a87c
|
7
|
+
data.tar.gz: a2860fb0258b96d95e5ca98f7d13b382c86b635ce1c2d97084c1f651a55973d2ffe31e360695fdec963292081e527b96876c6b42976a90573b9201e14032d1f5
|
data/.travis.yml
CHANGED
@@ -13,11 +13,26 @@ services:
|
|
13
13
|
# necessary.
|
14
14
|
before_script:
|
15
15
|
- unset RAILS_ENV
|
16
|
-
|
16
|
+
|
17
|
+
cache:
|
18
|
+
bundler: true
|
19
|
+
directories:
|
20
|
+
- $HOME/docker
|
21
|
+
|
22
|
+
# https://stackoverflow.com/a/41975912
|
23
|
+
before_cache:
|
24
|
+
# Save tagged docker images
|
25
|
+
- >
|
26
|
+
mkdir -p $HOME/docker && docker images -a --filter='dangling=false' --format '{{.Repository}}:{{.Tag}} {{.ID}}'
|
27
|
+
| xargs -n 2 -t sh -c 'test -e $HOME/docker/$1.tar.gz || docker save $0 | gzip -2 > $HOME/docker/$1.tar.gz'
|
28
|
+
|
29
|
+
before_install:
|
30
|
+
# Load cached docker images
|
31
|
+
- if [[ -d $HOME/docker ]]; then ls $HOME/docker/*.tar.gz | xargs -I {file} sh -c "zcat {file} | docker load"; fi
|
32
|
+
|
17
33
|
jobs:
|
18
34
|
include:
|
19
35
|
- stage: test
|
20
36
|
script:
|
21
37
|
- mkdir tmp
|
22
38
|
- bundle exec rake test
|
23
|
-
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,34 @@
|
|
1
|
+
# v0.44.0
|
2
|
+
|
3
|
+
* Support recording and labeling of indivudal functions via `functions:` section in *appmap.yml*.
|
4
|
+
* Remove deprecated `exe/appmap`.
|
5
|
+
* Add `test_status` and `exception` fields to AppMap metadata.
|
6
|
+
* Write AppMap file atomically, by writing to a temp file first and then moving it into place.
|
7
|
+
* Remove printing of `Inventory.json` file.
|
8
|
+
* Remove source code from `classMap`.
|
9
|
+
|
10
|
+
# v0.43.0
|
11
|
+
|
12
|
+
* Record `name` and `class` of each entry in Hash-like parameters, messages, and return values.
|
13
|
+
* Record client-sent headers in HTTP server request and response.
|
14
|
+
* Record HTTP server request `mime_type`.
|
15
|
+
* Record HTTP server request `authorization`.
|
16
|
+
|
17
|
+
# v0.42.1
|
18
|
+
|
19
|
+
* Add missing require `set`.
|
20
|
+
* Check `cls.respond_to?(:singleton_class)`, since it oddly, may not.
|
21
|
+
|
22
|
+
# v0.42.0
|
23
|
+
|
24
|
+
* Remove `feature_group` and `feature` metadata from minitest and RSpec AppMaps.
|
25
|
+
* Add `metadata.source_location`.
|
26
|
+
|
27
|
+
# v0.41.2
|
28
|
+
|
29
|
+
* Don't rely on `gemspec.source_paths` to list all the source locations in a gem. Hook any code that's loaded
|
30
|
+
from inside the `gem_dir`.
|
31
|
+
|
1
32
|
# v0.41.1
|
2
33
|
|
3
34
|
* Make best effort to ensure that class name is not `null` in the appmap.json.
|
data/README.md
CHANGED
@@ -11,6 +11,7 @@
|
|
11
11
|
- [Remote recording](#remote-recording)
|
12
12
|
- [Server process recording](#server-process-recording)
|
13
13
|
- [AppMap for VSCode](#appmap-for-vscode)
|
14
|
+
- [AppMap Swagger](#appmap-swagger)
|
14
15
|
- [Uploading AppMaps](#uploading-appmaps)
|
15
16
|
- [Development](#development)
|
16
17
|
- [Running tests](#running-tests)
|
@@ -82,6 +83,22 @@ If you are using Ruby on Rails, require the railtie after Rails is loaded.
|
|
82
83
|
require 'appmap/railtie' if defined?(AppMap).
|
83
84
|
```
|
84
85
|
|
86
|
+
**application.rb**
|
87
|
+
|
88
|
+
Add this line to *application.rb*, to enable server recording with `APPMAP_RECORD=true`:
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
module MyApp
|
92
|
+
class Application < Rails::Application
|
93
|
+
...
|
94
|
+
|
95
|
+
config.appmap.enabled = true if ENV['APPMAP_RECORD']
|
96
|
+
|
97
|
+
...
|
98
|
+
end
|
99
|
+
end
|
100
|
+
```
|
101
|
+
|
85
102
|
# Configuration
|
86
103
|
|
87
104
|
When you run your program, the `appmap` gem reads configuration settings from `appmap.yml`. Here's a sample configuration
|
@@ -93,6 +110,9 @@ name: my_project
|
|
93
110
|
packages:
|
94
111
|
- path: app/controllers
|
95
112
|
- path: app/models
|
113
|
+
# Exclude sub-paths within the package path
|
114
|
+
exclude:
|
115
|
+
- concerns/accessor
|
96
116
|
- path: app/jobs
|
97
117
|
- path: app/helpers
|
98
118
|
# Include the gems that you want to see in the dependency maps.
|
@@ -101,15 +121,22 @@ packages:
|
|
101
121
|
- gem: devise
|
102
122
|
- gem: aws-sdk
|
103
123
|
- gem: will_paginate
|
124
|
+
# Global exclusion of a class name
|
104
125
|
exclude:
|
105
126
|
- MyClass
|
106
127
|
- MyClass#my_instance_method
|
107
128
|
- MyClass.my_class_method
|
129
|
+
functions:
|
130
|
+
- packages: myapp
|
131
|
+
class: ControllerHelper
|
132
|
+
function: logged_in_user
|
133
|
+
labels: [ authentication ]
|
108
134
|
```
|
109
135
|
|
110
136
|
* **name** Provides the project name (required)
|
111
137
|
* **packages** A list of source code directories which should be recorded.
|
112
138
|
* **exclude** A list of classes and/or methods to definitively exclude from recording.
|
139
|
+
* **functions** A list of specific functions, scoped by package and class, to record.
|
113
140
|
|
114
141
|
**packages**
|
115
142
|
|
@@ -128,6 +155,11 @@ Each entry in the `packages` list is a YAML object which has the following keys:
|
|
128
155
|
|
129
156
|
Optional list of fully qualified class and method names. Separate class and method names with period (`.`) for class methods and hash (`#`) for instance methods.
|
130
157
|
|
158
|
+
**functions**
|
159
|
+
|
160
|
+
Optional list of `class, function` pairs. The `package` name is used to place the function within the class map, and does not have to match
|
161
|
+
the folder or gem name. The primary use of `functions` is to apply specific labels to functions whose source code is not accessible (e.g., it's in a Gem).
|
162
|
+
For functions which are part of the application code, use `@label` or `@labels` in code comments to apply labels.
|
131
163
|
|
132
164
|
# Labels
|
133
165
|
|
@@ -309,27 +341,24 @@ $ bundle exec rails server
|
|
309
341
|
|
310
342
|
## Server process recording
|
311
343
|
|
312
|
-
|
313
|
-
|
314
|
-
```ruby
|
315
|
-
module MyApp
|
316
|
-
class Application < Rails::Application
|
317
|
-
...
|
318
|
-
|
319
|
-
config.appmap.enabled = true if ENV['APPMAP_RECORD']
|
320
|
-
|
321
|
-
...
|
322
|
-
end
|
323
|
-
end
|
324
|
-
```
|
325
|
-
|
326
|
-
With this setting, you can run your Rails server with `APPMAP_RECORD=true`. When the server exits, an *appmap.json* file will be written to the project directory. This is a great way to start the server, interact with your app as a user (or through it's API), and then view an AppMap of everything that happened.
|
344
|
+
Run your Rails server with `APPMAP_RECORD=true`. When the server exits, an *appmap.json* file will be written to the project directory. This is a great way to start the server, interact with your app as a user (or through it's API), and then view an AppMap of everything that happened.
|
327
345
|
|
328
346
|
Be sure and set `WEB_CONCURRENCY=1`, if you are using a webserver that can run multiple processes. You only want there to be one process while you are recording, otherwise they will both try and write *appmap.json* and one of them will clobber the other.
|
329
347
|
|
348
|
+
|
330
349
|
# AppMap for VSCode
|
331
350
|
|
332
|
-
The [AppMap extension for VSCode](https://marketplace.visualstudio.com/items?itemName=appland.appmap)
|
351
|
+
The [AppMap extension for VSCode](https://marketplace.visualstudio.com/items?itemName=appland.appmap) helps you navigate your code more efficiently with interactive, accurate software architecture diagrams right in your IDE. In less than two minutes you can go from installing the AppMap extension to exploring maps of your code's architecture. AppMap helps you:
|
352
|
+
|
353
|
+
* Onboard to code architecture, with no extra work for the team
|
354
|
+
* Conduct code and design reviews using live and accurate data
|
355
|
+
* Troubleshoot hard-to-understand bugs using a "top-down" approach.
|
356
|
+
|
357
|
+
Each interactive diagram links directly to the source code, and the information is easy to share.
|
358
|
+
|
359
|
+
# AppMap Swagger
|
360
|
+
|
361
|
+
[appmap_swagger](https://github.com/applandinc/appmap_swagger-ruby) is a tool to generate Swagger files from AppMap data. With `appmap_swagger`, you can add Swagger to your Ruby or Ruby on Rails project, with no need to write or modify code. Use the Swagger UI to interact with your web services API as you build it, and use diffs of Swagger to perform code review of web service changes.
|
333
362
|
|
334
363
|
# Uploading AppMaps
|
335
364
|
|
@@ -338,7 +367,7 @@ The [AppMap extension for VSCode](https://marketplace.visualstudio.com/items?ite
|
|
338
367
|
For instructions on uploading, see the documentation of the [AppLand CLI](https://github.com/applandinc/appland-cli).
|
339
368
|
|
340
369
|
# Development
|
341
|
-
[![Build Status](https://travis-ci.
|
370
|
+
[![Build Status](https://travis-ci.com/applandinc/appmap-ruby.svg?branch=master)](https://travis-ci.com/applandinc/appmap-ruby)
|
342
371
|
|
343
372
|
## Running tests
|
344
373
|
|
@@ -367,7 +396,7 @@ The fixture apps in `test/fixtures` are plain Ruby projects that exercise the ba
|
|
367
396
|
|
368
397
|
### `spec/fixtures`
|
369
398
|
|
370
|
-
The fixture apps in `spec/fixtures` are simple Rack,
|
399
|
+
The fixture apps in `spec/fixtures` are simple Rack, Rails5, and Rails6 apps.
|
371
400
|
You can use them to interactively develop and test the recording features of the `appmap` gem.
|
372
401
|
These fixture apps are more sophisticated than `test/fixtures`, because they include additional
|
373
402
|
resources such as a PostgreSQL database.
|
@@ -393,11 +422,15 @@ $ docker-compose run --rm app ./create_app
|
|
393
422
|
Now you can start a development container.
|
394
423
|
|
395
424
|
```sh-session
|
396
|
-
$ docker-compose run --rm -v $PWD/../../..:/src/appmap-ruby app bash
|
425
|
+
$ docker-compose run --rm -v $PWD:/app -v $PWD/../../..:/src/appmap-ruby app bash
|
397
426
|
Starting rails_users_app_pg_1 ... done
|
398
|
-
root@6fab5f89125f:/app# cd /src/
|
427
|
+
root@6fab5f89125f:/app# cd /src/appmap-ruby
|
428
|
+
root@6fab5f89125f:/src/appmap-ruby# rm ext/appmap/*.so ext/appmap/*.o
|
429
|
+
root@6fab5f89125f:/src/appmap-ruby# bundle
|
430
|
+
root@6fab5f89125f:/src/appmap-ruby# bundle exec rake compile
|
431
|
+
root@6fab5f89125f:/src/appmap-ruby# cd /src/app
|
399
432
|
root@6fab5f89125f:/src/app# bundle config local.appmap /src/appmap-ruby
|
400
|
-
root@6fab5f89125f:/src/app# bundle
|
433
|
+
root@6fab5f89125f:/src/app# bundle
|
401
434
|
```
|
402
435
|
|
403
436
|
At this point, the bundle is built with the `appmap` gem located in `/src/appmap`, which is volume-mounted from the host.
|
@@ -412,4 +445,3 @@ Configuring AppMap from path appmap.yml
|
|
412
445
|
Finished in 0.07357 seconds (files took 2.1 seconds to load)
|
413
446
|
4 examples, 0 failures
|
414
447
|
```
|
415
|
-
|
data/appmap.gemspec
CHANGED
data/lib/appmap.rb
CHANGED
@@ -43,6 +43,7 @@ module AppMap
|
|
43
43
|
# Call this function before the program code is loaded by the Ruby VM, otherwise
|
44
44
|
# the load events won't be seen and the hooks won't activate.
|
45
45
|
def initialize(config_file_path = 'appmap.yml')
|
46
|
+
raise "AppMap configuration file #{config_file_path} does not exist" unless ::File.exists?(config_file_path)
|
46
47
|
warn "Configuring AppMap from path #{config_file_path}"
|
47
48
|
Config.load_from_file(config_file_path).tap do |configuration|
|
48
49
|
self.configuration = configuration
|
@@ -83,8 +84,8 @@ module AppMap
|
|
83
84
|
end
|
84
85
|
|
85
86
|
# Builds a class map from a config and a list of Ruby methods.
|
86
|
-
def class_map(methods
|
87
|
-
ClassMap.build_from_methods(methods
|
87
|
+
def class_map(methods)
|
88
|
+
ClassMap.build_from_methods(methods)
|
88
89
|
end
|
89
90
|
|
90
91
|
# Returns default metadata detected from the Ruby system and from the
|
data/lib/appmap/class_map.rb
CHANGED
@@ -71,17 +71,17 @@ module AppMap
|
|
71
71
|
end
|
72
72
|
|
73
73
|
class << self
|
74
|
-
def build_from_methods(methods
|
74
|
+
def build_from_methods(methods)
|
75
75
|
root = Types::Root.new
|
76
76
|
methods.each do |method|
|
77
|
-
add_function root, method
|
77
|
+
add_function root, method
|
78
78
|
end
|
79
79
|
root.children.map(&:to_h)
|
80
80
|
end
|
81
81
|
|
82
82
|
protected
|
83
83
|
|
84
|
-
def add_function(root, method
|
84
|
+
def add_function(root, method)
|
85
85
|
package = method.package
|
86
86
|
static = method.static
|
87
87
|
|
@@ -113,16 +113,13 @@ module AppMap
|
|
113
113
|
[ method.defined_class, static ? '.' : '#', method.name ].join
|
114
114
|
end
|
115
115
|
|
116
|
-
|
117
|
-
|
116
|
+
comment = begin
|
117
|
+
method.comment
|
118
118
|
rescue MethodSource::SourceNotFoundError
|
119
|
-
|
119
|
+
nil
|
120
120
|
end
|
121
121
|
|
122
|
-
|
123
|
-
function_info[:source] = source unless source.blank?
|
124
|
-
function_info[:comment] = comment unless comment.blank?
|
125
|
-
end
|
122
|
+
function_info[:comment] = comment unless comment.blank?
|
126
123
|
|
127
124
|
function_info[:labels] = parse_labels(comment) + (package.labels || [])
|
128
125
|
object_infos << function_info
|
data/lib/appmap/config.rb
CHANGED
@@ -20,20 +20,16 @@ module AppMap
|
|
20
20
|
warn "WARNING: #{gem} cannot be AppMapped because it is a dependency of the appmap gem"
|
21
21
|
return
|
22
22
|
end
|
23
|
-
|
24
|
-
Package.new(gem_path, gem, package_name, exclude, labels, shallow)
|
25
|
-
end
|
23
|
+
Package.new(gem_path(gem), gem, package_name, exclude, labels, shallow)
|
26
24
|
end
|
27
25
|
|
28
26
|
private_class_method :new
|
29
27
|
|
30
28
|
protected
|
31
29
|
|
32
|
-
def
|
30
|
+
def gem_path(gem)
|
33
31
|
gemspec = Gem.loaded_specs[gem] or raise "Gem #{gem.inspect} not found"
|
34
|
-
gemspec.
|
35
|
-
File.join(gemspec.gem_dir, path)
|
36
|
-
end
|
32
|
+
gemspec.gem_dir
|
37
33
|
end
|
38
34
|
end
|
39
35
|
|
@@ -53,40 +49,89 @@ module AppMap
|
|
53
49
|
end
|
54
50
|
end
|
55
51
|
|
56
|
-
|
52
|
+
Function = Struct.new(:package, :cls, :labels, :function_names) do
|
53
|
+
def to_h
|
54
|
+
{
|
55
|
+
package: package,
|
56
|
+
class: cls,
|
57
|
+
labels: labels,
|
58
|
+
functions: function_names.map(&:to_sym)
|
59
|
+
}.compact
|
60
|
+
end
|
57
61
|
end
|
58
62
|
|
59
|
-
|
63
|
+
class Hook
|
64
|
+
attr_reader :method_names, :package
|
65
|
+
|
66
|
+
def initialize(method_names, package)
|
67
|
+
@method_names = method_names
|
68
|
+
@package = package
|
69
|
+
end
|
70
|
+
|
71
|
+
def to_h
|
72
|
+
{
|
73
|
+
package: package.name,
|
74
|
+
method_names: method_names
|
75
|
+
}
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
OPENSSL_PACKAGES = ->(labels) { Package.build_from_path('openssl', package_name: 'openssl', labels: labels) }
|
60
80
|
|
61
81
|
# Methods that should always be hooked, with their containing
|
62
82
|
# package and labels that should be applied to them.
|
63
83
|
HOOKED_METHODS = {
|
64
|
-
'ActiveSupport::SecurityUtils' => Hook.new(:secure_compare, Package.build_from_path('active_support',
|
65
|
-
'ActionView::Renderer' => Hook.new(:render, Package.build_from_path('action_view',
|
84
|
+
'ActiveSupport::SecurityUtils' => Hook.new(:secure_compare, Package.build_from_path('active_support', labels: %w[crypto.secure_compare])),
|
85
|
+
'ActionView::Renderer' => Hook.new(:render, Package.build_from_path('action_view', labels: %w[mvc.view])),
|
86
|
+
'ActionDispatch::Request::Session' => Hook.new(%i[destroy [] dig values []= clear update delete fetch merge], Package.build_from_path('action_pack', labels: %w[http.session])),
|
87
|
+
'ActionDispatch::Cookies::CookieJar' => Hook.new(%i[[]= clear update delete recycle], Package.build_from_path('action_pack', labels: %w[http.cookie])),
|
88
|
+
'ActionDispatch::Cookies::EncryptedCookieJar' => Hook.new(%i[[]=], Package.build_from_path('action_pack', labels: %w[http.cookie crypto.encrypt])),
|
89
|
+
'CanCan::ControllerAdditions' => Hook.new(%i[authorize! can? cannot?], Package.build_from_path('cancancan', labels: %w[security.authorization])),
|
90
|
+
'CanCan::Ability' => Hook.new(%i[authorize!], Package.build_from_path('cancancan', labels: %w[security.authorization])),
|
91
|
+
'ActionController::Instrumentation' => [
|
92
|
+
Hook.new(%i[process_action send_file send_data redirect_to], Package.build_from_path('action_view', labels: %w[mvc.controller])),
|
93
|
+
Hook.new(%i[render], Package.build_from_path('action_view', labels: %w[mvc.view])),
|
94
|
+
]
|
66
95
|
}.freeze
|
67
96
|
|
68
97
|
BUILTIN_METHODS = {
|
69
|
-
'OpenSSL::PKey::PKey' => Hook.new(:sign, OPENSSL_PACKAGES),
|
70
|
-
'OpenSSL::X509::Request' => Hook.new(%i[sign verify], OPENSSL_PACKAGES),
|
71
|
-
'OpenSSL::PKCS5' => Hook.new(%i[pbkdf2_hmac_sha1 pbkdf2_hmac], OPENSSL_PACKAGES),
|
72
|
-
'OpenSSL::Cipher' =>
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
'
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
'
|
81
|
-
'
|
98
|
+
'OpenSSL::PKey::PKey' => Hook.new(:sign, OPENSSL_PACKAGES.(%w[crypto.pkey])),
|
99
|
+
'OpenSSL::X509::Request' => Hook.new(%i[sign verify], OPENSSL_PACKAGES.(%w[crypto.x509])),
|
100
|
+
'OpenSSL::PKCS5' => Hook.new(%i[pbkdf2_hmac_sha1 pbkdf2_hmac], OPENSSL_PACKAGES.(%w[crypto.pkcs5])),
|
101
|
+
'OpenSSL::Cipher' => [
|
102
|
+
Hook.new(%i[encrypt], OPENSSL_PACKAGES.(%w[crypto.encrypt])),
|
103
|
+
Hook.new(%i[decrypt], OPENSSL_PACKAGES.(%w[crypto.decrypt]))
|
104
|
+
],
|
105
|
+
'ActiveSupport::Callbacks::CallbackSequence' => [
|
106
|
+
Hook.new(:invoke_before, Package.build_from_path('active_support', package_name: 'active_support', labels: %w[mvc.before_action])),
|
107
|
+
Hook.new(:invoke_after, Package.build_from_path('active_support', package_name: 'active_support', labels: %w[mvc.after_action])),
|
108
|
+
],
|
109
|
+
'OpenSSL::X509::Certificate' => Hook.new(:sign, OPENSSL_PACKAGES.(%w[crypto.x509])),
|
110
|
+
'Net::HTTP' => Hook.new(:request, Package.build_from_path('net/http', package_name: 'net/http', labels: %w[protocol.http])),
|
111
|
+
'Net::SMTP' => Hook.new(:send, Package.build_from_path('net/smtp', package_name: 'net/smtp', labels: %w[protocol.email.smtp])),
|
112
|
+
'Net::POP3' => Hook.new(:mails, Package.build_from_path('net/pop3', package_name: 'net/pop', labels: %w[protocol.email.pop])),
|
113
|
+
'Net::IMAP' => Hook.new(:send_command, Package.build_from_path('net/imap', package_name: 'net/imap', labels: %w[protocol.email.imap])),
|
114
|
+
'Marshal' => Hook.new(%i[dump load], Package.build_from_path('marshal', labels: %w[format.marshal])),
|
115
|
+
'Psych' => Hook.new(%i[dump dump_stream load load_stream parse parse_stream], Package.build_from_path('yaml', package_name: 'psych', labels: %w[format.yaml])),
|
116
|
+
'JSON::Ext::Parser' => Hook.new(:parse, Package.build_from_path('json', package_name: 'json', labels: %w[format.json])),
|
117
|
+
'JSON::Ext::Generator::State' => Hook.new(:generate, Package.build_from_path('json', package_name: 'json', labels: %w[format.json])),
|
82
118
|
}.freeze
|
83
119
|
|
84
|
-
attr_reader :name, :packages, :exclude
|
120
|
+
attr_reader :name, :packages, :exclude, :builtin_methods
|
85
121
|
|
86
|
-
def initialize(name, packages
|
122
|
+
def initialize(name, packages, exclude: [], functions: [])
|
87
123
|
@name = name
|
88
124
|
@packages = packages
|
89
125
|
@exclude = exclude
|
126
|
+
@builtin_methods = BUILTIN_METHODS
|
127
|
+
@functions = functions
|
128
|
+
@hooked_methods = HOOKED_METHODS.dup
|
129
|
+
functions.each do |func|
|
130
|
+
package_options = {}
|
131
|
+
package_options[:labels] = func.labels if func.labels
|
132
|
+
@hooked_methods[func.cls] ||= []
|
133
|
+
@hooked_methods[func.cls] << Hook.new(func.function_names, Package.build_from_path(func.package, package_options))
|
134
|
+
end
|
90
135
|
end
|
91
136
|
|
92
137
|
class << self
|
@@ -98,6 +143,16 @@ module AppMap
|
|
98
143
|
|
99
144
|
# Loads configuration from a Hash.
|
100
145
|
def load(config_data)
|
146
|
+
functions = (config_data['functions'] || []).map do |function_data|
|
147
|
+
package = function_data['package']
|
148
|
+
cls = function_data['class']
|
149
|
+
functions = function_data['function'] || function_data['functions']
|
150
|
+
raise 'AppMap class configuration should specify package, class and function(s)' unless package && cls && functions
|
151
|
+
functions = Array(functions).map(&:to_sym)
|
152
|
+
labels = function_data['label'] || function_data['labels']
|
153
|
+
labels = Array(labels).map(&:to_s) if labels
|
154
|
+
Function.new(package, cls, labels, functions)
|
155
|
+
end
|
101
156
|
packages = (config_data['packages'] || []).map do |package|
|
102
157
|
gem = package['gem']
|
103
158
|
path = package['path']
|
@@ -109,10 +164,11 @@ module AppMap
|
|
109
164
|
shallow = true if shallow.nil?
|
110
165
|
Package.build_from_gem(gem, exclude: package['exclude'] || [], shallow: shallow)
|
111
166
|
else
|
112
|
-
|
167
|
+
Package.build_from_path(path, exclude: package['exclude'] || [], shallow: package['shallow'])
|
113
168
|
end
|
114
|
-
end.
|
115
|
-
|
169
|
+
end.compact
|
170
|
+
exclude = config_data['exclude'] || []
|
171
|
+
Config.new config_data['name'], packages, exclude: exclude, functions: functions
|
116
172
|
end
|
117
173
|
end
|
118
174
|
|
@@ -120,6 +176,7 @@ module AppMap
|
|
120
176
|
{
|
121
177
|
name: name,
|
122
178
|
packages: packages.map(&:to_h),
|
179
|
+
functions: @functions.map(&:to_h),
|
123
180
|
exclude: exclude
|
124
181
|
}
|
125
182
|
end
|
@@ -164,14 +221,17 @@ module AppMap
|
|
164
221
|
end
|
165
222
|
|
166
223
|
def find_package(defined_class, method_name)
|
167
|
-
|
168
|
-
return nil unless
|
224
|
+
hooks = find_hooks(defined_class)
|
225
|
+
return nil unless hooks
|
169
226
|
|
170
|
-
Array(
|
227
|
+
hook = Array(hooks).find do |hook|
|
228
|
+
Array(hook.method_names).include?(method_name)
|
229
|
+
end
|
230
|
+
hook ? hook.package : nil
|
171
231
|
end
|
172
232
|
|
173
|
-
def
|
174
|
-
|
233
|
+
def find_hooks(defined_class)
|
234
|
+
Array(@hooked_methods[defined_class] || @builtin_methods[defined_class])
|
175
235
|
end
|
176
236
|
end
|
177
237
|
end
|