appmap 0.23.0 → 0.25.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/.gitignore +1 -0
- data/.rubocop.yml +17 -8
- data/.travis.yml +6 -0
- data/CHANGELOG.md +19 -0
- data/README.md +29 -12
- data/Rakefile +3 -3
- data/appmap.gemspec +3 -1
- data/exe/appmap +6 -18
- data/lib/appmap.rb +47 -6
- data/lib/appmap/algorithm/prune_class_map.rb +2 -0
- data/lib/appmap/algorithm/stats.rb +4 -2
- data/lib/appmap/class_map.rb +143 -0
- data/lib/appmap/command/record.rb +8 -6
- data/lib/appmap/command/stats.rb +2 -0
- data/lib/appmap/command/upload.rb +4 -2
- data/lib/appmap/event.rb +168 -0
- data/lib/appmap/hook.rb +151 -0
- data/lib/appmap/middleware/remote_recording.rb +14 -20
- data/lib/appmap/rails/action_handler.rb +10 -6
- data/lib/appmap/rails/sql_handler.rb +10 -8
- data/lib/appmap/railtie.rb +31 -18
- data/lib/appmap/rspec.rb +238 -261
- data/lib/appmap/trace.rb +88 -0
- data/lib/appmap/version.rb +1 -1
- data/package-lock.json +90 -92
- data/spec/abstract_controller4_base_spec.rb +1 -1
- data/spec/abstract_controller_base_spec.rb +7 -3
- data/spec/config_spec.rb +25 -0
- data/spec/fixtures/hook/attr_accessor.rb +5 -0
- data/spec/fixtures/hook/class_method.rb +17 -0
- data/spec/fixtures/hook/constructor.rb +7 -0
- data/spec/fixtures/hook/exception_method.rb +11 -0
- data/spec/fixtures/hook/instance_method.rb +23 -0
- data/spec/fixtures/rails4_users_app/app/controllers/api/users_controller.rb +3 -3
- data/spec/fixtures/rails4_users_app/config/database.yml +2 -1
- data/spec/fixtures/rails4_users_app/docker-compose.yml +2 -0
- data/spec/fixtures/rails_users_app/.ruby-version +1 -1
- data/spec/fixtures/rails_users_app/app/controllers/api/users_controller.rb +2 -2
- data/spec/fixtures/rails_users_app/config/database.yml +2 -1
- data/spec/fixtures/rails_users_app/create_app +1 -0
- data/spec/fixtures/rails_users_app/docker-compose.yml +4 -0
- data/spec/fixtures/rails_users_app/spec/models/user_spec.rb +1 -1
- data/spec/hook_spec.rb +357 -0
- data/spec/rails_spec_helper.rb +25 -16
- data/spec/railtie_spec.rb +1 -1
- data/spec/record_sql_rails_pg_spec.rb +1 -2
- data/spec/remote_recording_spec.rb +117 -0
- data/spec/spec_helper.rb +1 -0
- data/test/cli_test.rb +7 -36
- data/test/fixtures/cli_record_test/appmap.yml +2 -1
- data/test/fixtures/cli_record_test/lib/cli_record_test/main.rb +4 -2
- data/test/test_helper.rb +0 -42
- metadata +46 -62
- data/exe/_appmap-record-self +0 -49
- data/lib/appmap/command/inspect.rb +0 -14
- data/lib/appmap/config.rb +0 -65
- data/lib/appmap/config/directory.rb +0 -65
- data/lib/appmap/config/file.rb +0 -13
- data/lib/appmap/config/named_function.rb +0 -21
- data/lib/appmap/config/package_dir.rb +0 -52
- data/lib/appmap/config/path.rb +0 -25
- data/lib/appmap/feature.rb +0 -262
- data/lib/appmap/inspect.rb +0 -91
- data/lib/appmap/inspect/inspector.rb +0 -99
- data/lib/appmap/inspect/parse_node.rb +0 -170
- data/lib/appmap/inspect/parser.rb +0 -15
- data/lib/appmap/parser.rb +0 -60
- data/lib/appmap/rspec/parse_node.rb +0 -41
- data/lib/appmap/rspec/parser.rb +0 -15
- data/lib/appmap/trace/event_handler/rack_handler_webrick.rb +0 -65
- data/lib/appmap/trace/tracer.rb +0 -356
- data/spec/fixtures/rails_users_app/bin/_appmap-record-self +0 -29
- data/spec/rack_handler_webrick_spec.rb +0 -59
- data/test/config_test.rb +0 -149
- data/test/explict_inspect_test.rb +0 -29
- data/test/fixtures/active_record_like/active_record.rb +0 -2
- data/test/fixtures/active_record_like/active_record/aggregations.rb +0 -4
- data/test/fixtures/active_record_like/active_record/association.rb +0 -4
- data/test/fixtures/active_record_like/active_record/associations/join_dependency.rb +0 -6
- data/test/fixtures/active_record_like/active_record/associations/join_dependency/join_base.rb +0 -8
- data/test/fixtures/active_record_like/active_record/associations/join_dependency/join_part.rb +0 -8
- data/test/fixtures/active_record_like/active_record/caps/caps.rb +0 -4
- data/test/fixtures/ignore_non_ruby_file/class.rb +0 -3
- data/test/fixtures/ignore_non_ruby_file/non-ruby.txt +0 -1
- data/test/fixtures/includes_excludes/lib/a/a_1.rb +0 -6
- data/test/fixtures/includes_excludes/lib/a/a_2.rb +0 -6
- data/test/fixtures/includes_excludes/lib/a/x/x_1.rb +0 -8
- data/test/fixtures/includes_excludes/lib/b/b_1.rb +0 -6
- data/test/fixtures/includes_excludes/lib/root_1.rb +0 -4
- data/test/fixtures/inspect_multiple_subdirs/module_a.rb +0 -2
- data/test/fixtures/inspect_multiple_subdirs/module_a/class_a.rb +0 -5
- data/test/fixtures/inspect_multiple_subdirs/module_b.rb +0 -2
- data/test/fixtures/inspect_multiple_subdirs/module_b/class_b.rb +0 -5
- data/test/fixtures/inspect_multiple_subdirs/module_b/class_c.rb +0 -5
- data/test/fixtures/inspect_package/module_a/module_b/class_in_module.rb +0 -6
- data/test/fixtures/parse_file/defs_static_function.rb +0 -96
- data/test/fixtures/parse_file/function_within_class.rb +0 -36
- data/test/fixtures/parse_file/include_public_methods.rb +0 -127
- data/test/fixtures/parse_file/instance_function.rb +0 -17
- data/test/fixtures/parse_file/modules.rb +0 -71
- data/test/fixtures/parse_file/sclass_static_function.rb +0 -88
- data/test/fixtures/parse_file/toplevel_class.rb +0 -13
- data/test/fixtures/parse_file/toplevel_function.rb +0 -14
- data/test/fixtures/trace_test/trace_program_1.rb +0 -44
- data/test/implicit_inspect_test.rb +0 -33
- data/test/include_exclude_test.rb +0 -48
- data/test/prerecorded_trace_test.rb +0 -76
- data/test/trace_test.rb +0 -92
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d42f8555b02b0478b8927c249f6dfa54c9326b7e3122cd5a0b91b5d1fb308fbb
|
|
4
|
+
data.tar.gz: 525faceacd156300098b897f7ef7789d94d42601f9ccec5d3bfad0f41b62ac54
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8290dde850c68b07c51baa70c074a283907c77c15093c8d6ed9b151da66f1dbad866f37beef6a12c2897195b8b18d147a839dd049336fd52fa1b48fb5e3d8ab1
|
|
7
|
+
data.tar.gz: '035025557325693fd0a158ce007dab265ec2646a3cf2e729f42348ac0986081f4356a1cec1e66c1bc7d9608025c6889b497e52ec6f510612a3fb5cedd220f22d'
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
|
@@ -1,18 +1,27 @@
|
|
|
1
|
-
|
|
1
|
+
Layout/SpaceInsideArrayLiteralBrackets:
|
|
2
2
|
Enabled: false
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
# We have squiggly heredocs
|
|
5
|
+
Layout/HeredocIndentation:
|
|
5
6
|
Enabled: false
|
|
6
7
|
|
|
7
|
-
Layout/
|
|
8
|
-
|
|
8
|
+
Layout/LineLength:
|
|
9
|
+
Max: 120
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
Layout/IndentHeredoc:
|
|
11
|
+
Style/MultilineBlockChain:
|
|
12
12
|
Enabled: false
|
|
13
13
|
|
|
14
|
+
Style/NumericPredicate:
|
|
15
|
+
Enabled: false
|
|
16
|
+
|
|
14
17
|
Style/AndOr:
|
|
15
18
|
Enabled: false
|
|
16
19
|
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
Style/HashEachMethods:
|
|
21
|
+
Enabled: true
|
|
22
|
+
|
|
23
|
+
Style/HashTransformKeys:
|
|
24
|
+
Enabled: true
|
|
25
|
+
|
|
26
|
+
Style/HashTransformValues:
|
|
27
|
+
Enabled: true
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,22 @@
|
|
|
1
|
+
# v0.25.0
|
|
2
|
+
|
|
3
|
+
* Reports `exceptions` in [function return attributes](https://github.com/applandinc/appmap#function-return-attributes).
|
|
4
|
+
|
|
5
|
+
# v0.24.1
|
|
6
|
+
* Fixes an issue which prevented a remote recording from returning scenario data successfully.
|
|
7
|
+
* Remote recording routes now return descriptive status codes as intended.
|
|
8
|
+
* Remote recording routes now have the correct `Content-Type` header.
|
|
9
|
+
|
|
10
|
+
# v0.24.0
|
|
11
|
+
|
|
12
|
+
Internals of `appmap-ruby` have been changed to record each method event using `alias_method`,
|
|
13
|
+
rather than `TracePoint`. Performance is much better as a result.
|
|
14
|
+
|
|
15
|
+
**WARNING** Breaking changes
|
|
16
|
+
|
|
17
|
+
* **Rack** apps no longer generate `http_server_request` events.
|
|
18
|
+
* **appmap inspect** has been removed. `appmap-ruby` no longer parses the source tree. Instead, it observes the methods as they are loaded by the VM. So, to get a class map, you have to create a recording. The `RSpec` recorder still prints an inventory to `Inventory.appmap.json` when it exits. The class map in this file contains every class and method which was loaded by any of the tests.
|
|
19
|
+
|
|
1
20
|
# v0.23.0
|
|
2
21
|
|
|
3
22
|
* **appmap stats** command added.
|
data/README.md
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
- [About](#about)
|
|
2
|
+
- [Testing](#testing)
|
|
2
3
|
- [Installation](#installation)
|
|
3
4
|
- [Configuration](#configuration)
|
|
4
5
|
- [Running](#running)
|
|
5
6
|
- [RSpec](#rspec)
|
|
6
7
|
- [Remote recording](#remote-recording)
|
|
8
|
+
- [Ruby on Rails](#ruby-on-rails)
|
|
7
9
|
- [Uploading AppMaps](#uploading-appmaps)
|
|
8
10
|
- [Build status](#build-status)
|
|
9
11
|
|
|
@@ -11,21 +13,33 @@
|
|
|
11
13
|
|
|
12
14
|
`appmap-ruby` is a Ruby Gem for recording and uploading
|
|
13
15
|
[AppMaps](https://github.com/applandinc/appmap) of your code.
|
|
14
|
-
AppMap is a data format which records code structure (modules, classes, and methods), code execution events
|
|
16
|
+
"AppMap" is a data format which records code structure (modules, classes, and methods), code execution events
|
|
15
17
|
(function calls and returns), and code metadata (repo name, repo URL, commit
|
|
16
|
-
SHA, etc). It's more granular than a performance profile, but it's less
|
|
18
|
+
SHA, labels, etc). It's more granular than a performance profile, but it's less
|
|
17
19
|
granular than a full debug trace. It's designed to be optimal for understanding the design intent and behavior of code.
|
|
18
20
|
|
|
19
21
|
There are several ways to record AppMaps of your Ruby program using the `appmap` gem:
|
|
20
22
|
|
|
21
|
-
* Run your RSpec tests
|
|
22
|
-
* Run your application server with AppMap remote recording enabled, and use the AppMap
|
|
23
|
+
* Run your RSpec tests with the environment variable `APPMAP=true`. An AppMap will be generated for each spec.
|
|
24
|
+
* Run your application server with AppMap remote recording enabled, and use the AppMap.
|
|
23
25
|
browser extension to start, stop, and upload recordings.
|
|
26
|
+
* Run the command `appmap record <program>` to record the entire execution of a program.
|
|
24
27
|
|
|
25
28
|
When you record AppMaps on the command line (for example, by running RSpec tests), you use the `appmap upload` command to
|
|
26
29
|
upload them to the AppLand website. On the AppLand website, you'll be able to
|
|
27
30
|
visualize the design of your code and share links with collaborators.
|
|
28
31
|
|
|
32
|
+
# Testing
|
|
33
|
+
Before running tests, configure `local.appmap` to point to your local `appmap-ruby` directory.
|
|
34
|
+
```
|
|
35
|
+
$ bundle config local.appmap $(pwd)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Run the tests via `rake`:
|
|
39
|
+
```
|
|
40
|
+
$ bundle exec rake test
|
|
41
|
+
```
|
|
42
|
+
|
|
29
43
|
# Installation
|
|
30
44
|
|
|
31
45
|
Add `gem 'appmap'` to your Gemfile just as you would any other dependency.
|
|
@@ -60,8 +74,6 @@ packages:
|
|
|
60
74
|
|
|
61
75
|
* **name** Provides the project name (required)
|
|
62
76
|
* **packages** A list of source code directories which should be instrumented.
|
|
63
|
-
* **files** A list of individual files which should be instrumented. This is only used for files which are
|
|
64
|
-
not part of the `packages` list.
|
|
65
77
|
|
|
66
78
|
**packages**
|
|
67
79
|
|
|
@@ -69,9 +81,7 @@ Each entry in the `packages` list is a YAML object which has the following keys:
|
|
|
69
81
|
|
|
70
82
|
* **path** The path to the source code directory. The path may be relative to the current working directory, or it may
|
|
71
83
|
be an absolute path.
|
|
72
|
-
* **
|
|
73
|
-
is located. In the example above, "controllers" or "models".
|
|
74
|
-
* **excludes** A list of files and directories which will be ignored. By default, all modules, classes and public
|
|
84
|
+
* **exclude** A list of files and directories which will be ignored. By default, all modules, classes and public
|
|
75
85
|
functions are inspected.
|
|
76
86
|
|
|
77
87
|
# Running
|
|
@@ -129,6 +139,8 @@ If you include the `feature` and `feature_group` metadata, these attributes will
|
|
|
129
139
|
}
|
|
130
140
|
```
|
|
131
141
|
|
|
142
|
+
If you don't explicitly declare `feature` and `feature_group`, then they will be inferred from the spec name and example descriptions.
|
|
143
|
+
|
|
132
144
|
## Remote recording
|
|
133
145
|
|
|
134
146
|
To manually record ad-hoc AppMaps of your Ruby app, use AppMap remote recording.
|
|
@@ -159,12 +171,18 @@ $ bundle exec rails server
|
|
|
159
171
|
|
|
160
172
|
6. Open the AppApp browser extension and push `Stop`. The recording will be transferred to the AppLand website and opened in your browser.
|
|
161
173
|
|
|
174
|
+
## Ruby on Rails
|
|
175
|
+
|
|
176
|
+
If your app uses Ruby on Rails, the AppMap Railtie will be automatically enabled. Set the Rails config flag `app.config.appmap.enabled = true` to record the entire execution of your Rails app.
|
|
177
|
+
|
|
178
|
+
Note that using this method is kind of a blunt instrument. Recording RSpecs and using Remote Recording are usually better options.
|
|
179
|
+
|
|
162
180
|
# Uploading AppMaps
|
|
163
181
|
|
|
164
|
-
To upload an AppMap file to AppLand, run the `appmap upload` command. For example:
|
|
182
|
+
To upload an AppMap file to AppLand, run the `appmap upload` command. For example (with binstubs installed):
|
|
165
183
|
|
|
166
184
|
```sh-session
|
|
167
|
-
$ appmap upload tmp/appmap/rspec
|
|
185
|
+
$ ./bin/appmap upload tmp/appmap/rspec/*
|
|
168
186
|
Uploading "tmp/appmap/rspec/Hello_app_says_hello_when_prompted.appmap.json"
|
|
169
187
|
Scenario Id: 4da4f267-bdea-48e8-bf67-f39463844230
|
|
170
188
|
Batch Id: a116f1df-ee57-4bde-8eef-851af0f3d7bc
|
|
@@ -172,4 +190,3 @@ Batch Id: a116f1df-ee57-4bde-8eef-851af0f3d7bc
|
|
|
172
190
|
|
|
173
191
|
# Build status
|
|
174
192
|
[](https://travis-ci.org/applandinc/appmap-ruby)
|
|
175
|
-
|
data/Rakefile
CHANGED
|
@@ -54,7 +54,7 @@ namespace :build do
|
|
|
54
54
|
end
|
|
55
55
|
end
|
|
56
56
|
end
|
|
57
|
-
|
|
57
|
+
|
|
58
58
|
namespace :fixtures do
|
|
59
59
|
RUBY_VERSIONS.each do |ruby_version|
|
|
60
60
|
namespace ruby_version do
|
|
@@ -69,7 +69,7 @@ namespace :build do
|
|
|
69
69
|
end
|
|
70
70
|
end
|
|
71
71
|
end
|
|
72
|
-
|
|
72
|
+
|
|
73
73
|
desc "Build all fixture images"
|
|
74
74
|
task all: ["#{ruby_version}:all"]
|
|
75
75
|
end
|
|
@@ -93,7 +93,7 @@ def run_specs(ruby_version, task_args)
|
|
|
93
93
|
task.rspec_opts = args.to_a.join(' ')
|
|
94
94
|
end
|
|
95
95
|
end
|
|
96
|
-
|
|
96
|
+
|
|
97
97
|
# Set up the environment, then execute the rspec task we
|
|
98
98
|
# created above.
|
|
99
99
|
ClimateControl.modify(RUBY_VERSION: ruby_version) do
|
data/appmap.gemspec
CHANGED
|
@@ -30,11 +30,13 @@ Gem::Specification.new do |spec|
|
|
|
30
30
|
spec.add_development_dependency 'bundler', '~> 1.16'
|
|
31
31
|
spec.add_development_dependency 'minitest', '~> 5.0'
|
|
32
32
|
spec.add_development_dependency 'pry-byebug'
|
|
33
|
-
spec.add_development_dependency 'rake', '
|
|
33
|
+
spec.add_development_dependency 'rake', '>= 12.3.3'
|
|
34
34
|
spec.add_development_dependency 'rdoc'
|
|
35
|
+
spec.add_development_dependency 'rubocop'
|
|
35
36
|
|
|
36
37
|
# Testing
|
|
37
38
|
spec.add_development_dependency 'climate_control'
|
|
39
|
+
spec.add_development_dependency 'diffy'
|
|
38
40
|
spec.add_development_dependency 'launchy'
|
|
39
41
|
spec.add_development_dependency 'rspec'
|
|
40
42
|
spec.add_development_dependency 'selenium-webdriver'
|
data/exe/appmap
CHANGED
|
@@ -42,17 +42,6 @@ module AppMap
|
|
|
42
42
|
arg_name 'filename'
|
|
43
43
|
flag %i[c config]
|
|
44
44
|
|
|
45
|
-
desc 'Inspect code and generate a classmap file'
|
|
46
|
-
command :inspect do |c|
|
|
47
|
-
output_file_flag(c, default_value: default_appmap_file)
|
|
48
|
-
|
|
49
|
-
c.action do
|
|
50
|
-
require 'appmap/command/inspect'
|
|
51
|
-
appmap = AppMap::Command::Inspect.new(@config).perform
|
|
52
|
-
@output_file.write JSON.pretty_generate(appmap)
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
|
|
56
45
|
desc 'Record the execution of a program and generate an AppMap.'
|
|
57
46
|
arg_name 'program'
|
|
58
47
|
command :record do |c|
|
|
@@ -76,10 +65,10 @@ module AppMap
|
|
|
76
65
|
ARGV.shift
|
|
77
66
|
|
|
78
67
|
require 'appmap/command/record'
|
|
79
|
-
AppMap::Command::Record.new(@config, program).perform do |
|
|
80
|
-
@output_file.write JSON.generate(version:
|
|
81
|
-
|
|
82
|
-
|
|
68
|
+
AppMap::Command::Record.new(@config, program).perform do |version, metadata, class_map, events|
|
|
69
|
+
@output_file.write JSON.generate(version: version,
|
|
70
|
+
metadata: metadata,
|
|
71
|
+
classMap: class_map,
|
|
83
72
|
events: events)
|
|
84
73
|
end
|
|
85
74
|
end
|
|
@@ -173,7 +162,7 @@ module AppMap
|
|
|
173
162
|
appmap = JSON.parse(File.read(filename))
|
|
174
163
|
|
|
175
164
|
warn "Uploading #{filename.inspect}"
|
|
176
|
-
upload = AppMap::Command::Upload.new(
|
|
165
|
+
upload = AppMap::Command::Upload.new(appmap, url, user, org)
|
|
177
166
|
upload.batch_id = batch_id if batch_id
|
|
178
167
|
upload.perform.tap do |response|
|
|
179
168
|
batch_id ||= response.batch_id
|
|
@@ -203,8 +192,7 @@ module AppMap
|
|
|
203
192
|
protected
|
|
204
193
|
|
|
205
194
|
def interpret_config_option(fname)
|
|
206
|
-
|
|
207
|
-
AppMap::Config.load_from_file fname
|
|
195
|
+
AppMap.configure fname
|
|
208
196
|
end
|
|
209
197
|
|
|
210
198
|
def interpret_output_file_option(file_name)
|
data/lib/appmap.rb
CHANGED
|
@@ -13,12 +13,53 @@ module AppMap
|
|
|
13
13
|
BATCH_HEADER_NAME = 'AppLand-Scenario-Batch'
|
|
14
14
|
|
|
15
15
|
class << self
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
@config = nil
|
|
17
|
+
@config_file_path = nil
|
|
18
|
+
|
|
19
|
+
# configuration gets the AppMap configuration.
|
|
20
|
+
def configuration
|
|
21
|
+
raise "AppMap is not configured" unless @config
|
|
22
|
+
|
|
23
|
+
@config
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# configure applies the configuration from a file. This method can only be performed once.
|
|
27
|
+
# Be sure and call it before +hook+ if you want non-default configuration.
|
|
28
|
+
#
|
|
29
|
+
# Default behavior is to configure from "appmap.yml".
|
|
30
|
+
def configure(config_file_path = 'appmap.yml')
|
|
31
|
+
if @config
|
|
32
|
+
return @config if @config_file_path == config_file_path
|
|
33
|
+
|
|
34
|
+
raise "AppMap is already configured from #{@config_file_path}, can't reconfigure from #{config_file_path}"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
warn "Configuring AppMap from path #{config_file_path}"
|
|
38
|
+
require 'appmap/hook'
|
|
39
|
+
AppMap::Hook::Config.load_from_file(config_file_path).tap do |config|
|
|
40
|
+
@config = config
|
|
41
|
+
@config_file_path = config_file_path
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Activate the code hooks which record function calls as trace events.
|
|
46
|
+
# Call this function before the program code is loaded by the Ruby VM, otherwise
|
|
47
|
+
# the load events won't be seen and the hooks won't activate.
|
|
48
|
+
def hook(config = configure)
|
|
49
|
+
require 'appmap/hook'
|
|
50
|
+
AppMap::Hook.hook(config)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Access the AppMap::Tracers, which can be used to start tracing, stop tracing, and record events.
|
|
54
|
+
def tracing
|
|
55
|
+
require 'appmap/trace'
|
|
56
|
+
@tracing ||= Trace::Tracers.new
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Build a class map from a config and a list of Ruby methods.
|
|
60
|
+
def class_map(config, methods)
|
|
61
|
+
require 'appmap/class_map'
|
|
62
|
+
AppMap::ClassMap.build_from_methods(config, methods)
|
|
22
63
|
end
|
|
23
64
|
end
|
|
24
65
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module AppMap
|
|
2
4
|
module Algorithm
|
|
3
5
|
StatsStruct = Struct.new(:appmap)
|
|
@@ -31,7 +33,7 @@ module AppMap
|
|
|
31
33
|
comparator = ->(a,b) { b.count <=> a.count }
|
|
32
34
|
class_frequency.sort!(&comparator)
|
|
33
35
|
method_frequency.sort!(&comparator)
|
|
34
|
-
|
|
36
|
+
|
|
35
37
|
self
|
|
36
38
|
end
|
|
37
39
|
|
|
@@ -55,7 +57,7 @@ module AppMap
|
|
|
55
57
|
end
|
|
56
58
|
end
|
|
57
59
|
Frequency = Struct.new(:name, :count)
|
|
58
|
-
|
|
60
|
+
|
|
59
61
|
def perform(limit: nil)
|
|
60
62
|
events = appmap['events'] || []
|
|
61
63
|
frequency_calc = lambda do |key_func|
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'active_support/core_ext'
|
|
4
|
+
|
|
5
|
+
module AppMap
|
|
6
|
+
class ClassMap
|
|
7
|
+
module HasChildren
|
|
8
|
+
def self.included(base)
|
|
9
|
+
base.module_eval do
|
|
10
|
+
def children
|
|
11
|
+
@children ||= []
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
module Types
|
|
18
|
+
class Root
|
|
19
|
+
include HasChildren
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
Package = Struct.new(:name) do
|
|
23
|
+
include HasChildren
|
|
24
|
+
|
|
25
|
+
def type
|
|
26
|
+
'package'
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def to_h
|
|
30
|
+
{
|
|
31
|
+
name: name,
|
|
32
|
+
type: type,
|
|
33
|
+
children: children.map(&:to_h)
|
|
34
|
+
}
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
Class = Struct.new(:name) do
|
|
38
|
+
include HasChildren
|
|
39
|
+
|
|
40
|
+
def type
|
|
41
|
+
'class'
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def to_h
|
|
45
|
+
{
|
|
46
|
+
name: name,
|
|
47
|
+
type: type,
|
|
48
|
+
children: children.map(&:to_h)
|
|
49
|
+
}
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
Function = Struct.new(:name) do
|
|
53
|
+
attr_accessor :static, :location
|
|
54
|
+
|
|
55
|
+
def type
|
|
56
|
+
'function'
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def to_h
|
|
60
|
+
{
|
|
61
|
+
name: name,
|
|
62
|
+
type: type,
|
|
63
|
+
location: location,
|
|
64
|
+
static: static
|
|
65
|
+
}
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
class << self
|
|
71
|
+
def build_from_methods(config, methods)
|
|
72
|
+
root = Types::Root.new
|
|
73
|
+
methods.each do |method|
|
|
74
|
+
package = package_for_method(config.packages, method)
|
|
75
|
+
add_function root, package.path, method
|
|
76
|
+
end
|
|
77
|
+
root.children.map(&:to_h)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
protected
|
|
81
|
+
|
|
82
|
+
def package_for_method(packages, method)
|
|
83
|
+
location = method.method.source_location
|
|
84
|
+
location_file, = location
|
|
85
|
+
location_file = location_file[Dir.pwd.length + 1..-1] if location_file.index(Dir.pwd) == 0
|
|
86
|
+
|
|
87
|
+
packages.find do |pkg|
|
|
88
|
+
(location_file.index(pkg.path) == 0) &&
|
|
89
|
+
!pkg.exclude.find { |p| location_file.index(p) }
|
|
90
|
+
end or raise "No package found for method #{method}"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def add_function(root, package_name, method)
|
|
94
|
+
location = method.method.source_location
|
|
95
|
+
location_file, lineno = location
|
|
96
|
+
location_file = location_file[Dir.pwd.length + 1..-1] if location_file.index(Dir.pwd) == 0
|
|
97
|
+
|
|
98
|
+
static = method.method.owner.singleton_class?
|
|
99
|
+
|
|
100
|
+
object_infos = [
|
|
101
|
+
{
|
|
102
|
+
name: package_name,
|
|
103
|
+
type: 'package'
|
|
104
|
+
}
|
|
105
|
+
]
|
|
106
|
+
object_infos += method.defined_class.split('::').map do |name|
|
|
107
|
+
{
|
|
108
|
+
name: name,
|
|
109
|
+
type: 'class'
|
|
110
|
+
}
|
|
111
|
+
end
|
|
112
|
+
object_infos << {
|
|
113
|
+
name: method.method.name,
|
|
114
|
+
type: 'function',
|
|
115
|
+
location: [ location_file, lineno ].join(':'),
|
|
116
|
+
static: static
|
|
117
|
+
}
|
|
118
|
+
parent = root
|
|
119
|
+
object_infos.each do |info|
|
|
120
|
+
parent = find_or_create parent.children, info do
|
|
121
|
+
Types.const_get(info[:type].classify).new(info[:name].to_s).tap do |type|
|
|
122
|
+
info.keys.tap do |keys|
|
|
123
|
+
keys.delete(:name)
|
|
124
|
+
keys.delete(:type)
|
|
125
|
+
end.each do |key|
|
|
126
|
+
type.send "#{key}=", info[key]
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def find_or_create(list, info)
|
|
134
|
+
obj = list.find { |item| item.type == info[:type] && item.name == info[:name] }
|
|
135
|
+
return obj if obj
|
|
136
|
+
|
|
137
|
+
yield.tap do |new_obj|
|
|
138
|
+
list << new_obj
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|