appmap 0.26.0 → 0.31.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 -2
- data/CHANGELOG.md +38 -0
- data/README.md +144 -31
- data/Rakefile +1 -1
- data/exe/appmap +3 -1
- data/lib/appmap.rb +55 -35
- data/lib/appmap/algorithm/stats.rb +2 -1
- data/lib/appmap/class_map.rb +16 -24
- data/lib/appmap/command/record.rb +2 -61
- data/lib/appmap/config.rb +91 -0
- data/lib/appmap/cucumber.rb +89 -0
- data/lib/appmap/event.rb +6 -6
- data/lib/appmap/hook.rb +94 -116
- data/lib/appmap/metadata.rb +62 -0
- data/lib/appmap/middleware/remote_recording.rb +2 -6
- data/lib/appmap/minitest.rb +141 -0
- data/lib/appmap/rails/action_handler.rb +2 -2
- data/lib/appmap/rails/sql_handler.rb +2 -2
- data/lib/appmap/railtie.rb +2 -2
- data/lib/appmap/record.rb +27 -0
- data/lib/appmap/rspec.rb +20 -38
- data/lib/appmap/trace.rb +19 -11
- data/lib/appmap/util.rb +40 -0
- data/lib/appmap/version.rb +1 -1
- data/package-lock.json +3 -3
- data/spec/abstract_controller4_base_spec.rb +1 -1
- data/spec/abstract_controller_base_spec.rb +1 -1
- data/spec/config_spec.rb +3 -3
- data/spec/fixtures/hook/compare.rb +7 -0
- data/spec/fixtures/hook/openssl_sign.rb +87 -0
- data/spec/fixtures/hook/singleton_method.rb +54 -0
- data/spec/fixtures/rails_users_app/Gemfile +1 -0
- data/spec/fixtures/rails_users_app/features/api_users.feature +13 -0
- data/spec/fixtures/rails_users_app/features/support/env.rb +4 -0
- data/spec/fixtures/rails_users_app/features/support/hooks.rb +11 -0
- data/spec/fixtures/rails_users_app/features/support/steps.rb +18 -0
- data/spec/hook_spec.rb +243 -36
- data/spec/rails_spec_helper.rb +2 -0
- data/spec/rspec_feature_metadata_spec.rb +2 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/util_spec.rb +21 -0
- data/test/cli_test.rb +2 -2
- data/test/cucumber_test.rb +72 -0
- data/test/fixtures/cucumber4_recorder/Gemfile +5 -0
- data/test/fixtures/cucumber4_recorder/appmap.yml +3 -0
- data/test/fixtures/cucumber4_recorder/features/say_hello.feature +5 -0
- data/test/fixtures/cucumber4_recorder/features/support/env.rb +5 -0
- data/test/fixtures/cucumber4_recorder/features/support/hooks.rb +11 -0
- data/test/fixtures/cucumber4_recorder/features/support/steps.rb +9 -0
- data/test/fixtures/cucumber4_recorder/lib/hello.rb +7 -0
- data/test/fixtures/cucumber_recorder/Gemfile +5 -0
- data/test/fixtures/cucumber_recorder/appmap.yml +3 -0
- data/test/fixtures/cucumber_recorder/features/say_hello.feature +5 -0
- data/test/fixtures/cucumber_recorder/features/support/env.rb +5 -0
- data/test/fixtures/cucumber_recorder/features/support/hooks.rb +11 -0
- data/test/fixtures/cucumber_recorder/features/support/steps.rb +9 -0
- data/test/fixtures/cucumber_recorder/lib/hello.rb +7 -0
- data/test/fixtures/minitest_recorder/Gemfile +5 -0
- data/test/fixtures/minitest_recorder/appmap.yml +3 -0
- data/test/fixtures/minitest_recorder/lib/hello.rb +5 -0
- data/test/fixtures/minitest_recorder/test/hello_test.rb +12 -0
- data/test/fixtures/process_recorder/appmap.yml +3 -0
- data/test/fixtures/process_recorder/hello.rb +9 -0
- data/test/fixtures/rspec_recorder/Gemfile +1 -1
- data/test/fixtures/rspec_recorder/spec/decorated_hello_spec.rb +12 -0
- data/test/minitest_test.rb +38 -0
- data/test/record_process_test.rb +35 -0
- data/test/rspec_test.rb +5 -0
- metadata +39 -3
- data/spec/fixtures/hook/class_method.rb +0 -17
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AppMap
|
4
|
+
module Metadata
|
5
|
+
class << self
|
6
|
+
def detect
|
7
|
+
{
|
8
|
+
app: AppMap.configuration.name,
|
9
|
+
language: {
|
10
|
+
name: 'ruby',
|
11
|
+
engine: RUBY_ENGINE,
|
12
|
+
version: RUBY_VERSION
|
13
|
+
},
|
14
|
+
client: {
|
15
|
+
name: 'appmap',
|
16
|
+
url: AppMap::URL,
|
17
|
+
version: AppMap::VERSION
|
18
|
+
}
|
19
|
+
}.tap do |m|
|
20
|
+
if defined?(::Rails) && defined?(::Rails.version)
|
21
|
+
m[:frameworks] ||= []
|
22
|
+
m[:frameworks] << {
|
23
|
+
name: 'rails',
|
24
|
+
version: ::Rails.version
|
25
|
+
}
|
26
|
+
end
|
27
|
+
m[:git] = git_metadata if git_available
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
protected
|
32
|
+
|
33
|
+
def git_available
|
34
|
+
@git_available = system('git status 2>&1 > /dev/null') if @git_available.nil?
|
35
|
+
end
|
36
|
+
|
37
|
+
def git_metadata
|
38
|
+
git_repo = `git config --get remote.origin.url`.strip
|
39
|
+
git_branch = `git rev-parse --abbrev-ref HEAD`.strip
|
40
|
+
git_sha = `git rev-parse HEAD`.strip
|
41
|
+
git_status = `git status -s`.split("\n").map(&:strip)
|
42
|
+
git_last_annotated_tag = `git describe --abbrev=0 2>/dev/null`.strip
|
43
|
+
git_last_annotated_tag = nil if git_last_annotated_tag.blank?
|
44
|
+
git_last_tag = `git describe --abbrev=0 --tags 2>/dev/null`.strip
|
45
|
+
git_last_tag = nil if git_last_tag.blank?
|
46
|
+
git_commits_since_last_annotated_tag = `git describe`.strip =~ /-(\d+)-(\w+)$/[1] rescue 0 if git_last_annotated_tag
|
47
|
+
git_commits_since_last_tag = `git describe --tags`.strip =~ /-(\d+)-(\w+)$/[1] rescue 0 if git_last_tag
|
48
|
+
|
49
|
+
{
|
50
|
+
repository: git_repo,
|
51
|
+
branch: git_branch,
|
52
|
+
commit: git_sha,
|
53
|
+
status: git_status,
|
54
|
+
git_last_annotated_tag: git_last_annotated_tag,
|
55
|
+
git_last_tag: git_last_tag,
|
56
|
+
git_commits_since_last_annotated_tag: git_commits_since_last_annotated_tag,
|
57
|
+
git_commits_since_last_tag: git_commits_since_last_tag
|
58
|
+
}
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -5,12 +5,9 @@ module AppMap
|
|
5
5
|
# RemoteRecording adds `/_appmap/record` routes to control recordings via HTTP requests
|
6
6
|
class RemoteRecording
|
7
7
|
def initialize(app)
|
8
|
-
require 'appmap/command/record'
|
9
8
|
require 'json'
|
10
9
|
|
11
10
|
@app = app
|
12
|
-
@config = AppMap.configure
|
13
|
-
AppMap::Hook.hook(@config)
|
14
11
|
end
|
15
12
|
|
16
13
|
def event_loop
|
@@ -63,15 +60,14 @@ module AppMap
|
|
63
60
|
@events.delete_if(&is_control_command_event)
|
64
61
|
@events.delete_if(&is_return_from_control_command_event)
|
65
62
|
|
66
|
-
|
67
|
-
metadata = AppMap::Command::Record.detect_metadata
|
63
|
+
metadata = AppMap.detect_metadata
|
68
64
|
metadata[:recorder] = {
|
69
65
|
name: 'remote_recording'
|
70
66
|
}
|
71
67
|
|
72
68
|
response = JSON.generate \
|
73
69
|
version: AppMap::APPMAP_FORMAT_VERSION,
|
74
|
-
classMap: AppMap.class_map(
|
70
|
+
classMap: AppMap.class_map(tracer.event_methods),
|
75
71
|
metadata: metadata,
|
76
72
|
events: @events
|
77
73
|
|
@@ -0,0 +1,141 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'appmap/util'
|
4
|
+
|
5
|
+
module AppMap
|
6
|
+
# Integration of AppMap with Minitest. When enabled with APPMAP=true, the AppMap tracer will
|
7
|
+
# be activated around each test.
|
8
|
+
module Minitest
|
9
|
+
APPMAP_OUTPUT_DIR = 'tmp/appmap/minitest'
|
10
|
+
LOG = false
|
11
|
+
|
12
|
+
def self.metadata
|
13
|
+
AppMap.detect_metadata
|
14
|
+
end
|
15
|
+
|
16
|
+
Recording = Struct.new(:test) do
|
17
|
+
def initialize(test)
|
18
|
+
super
|
19
|
+
|
20
|
+
warn "Starting recording of test #{test.class}.#{test.name}" if AppMap::Minitest::LOG
|
21
|
+
@trace = AppMap.tracing.trace
|
22
|
+
end
|
23
|
+
|
24
|
+
def finish
|
25
|
+
warn "Finishing recording of test #{test.class}.#{test.name}" if AppMap::Minitest::LOG
|
26
|
+
|
27
|
+
events = []
|
28
|
+
AppMap.tracing.delete @trace
|
29
|
+
|
30
|
+
events << @trace.next_event.to_h while @trace.event?
|
31
|
+
|
32
|
+
AppMap::Minitest.add_event_methods @trace.event_methods
|
33
|
+
|
34
|
+
class_map = AppMap.class_map(@trace.event_methods)
|
35
|
+
|
36
|
+
feature_group = test.class.name.underscore.split('_')[0...-1].join('_').capitalize
|
37
|
+
feature_name = test.name.split('_')[1..-1].join(' ')
|
38
|
+
scenario_name = [ feature_group, feature_name ].join(' ')
|
39
|
+
|
40
|
+
AppMap::Minitest.save scenario_name,
|
41
|
+
class_map,
|
42
|
+
events: events,
|
43
|
+
feature_name: feature_name,
|
44
|
+
feature_group_name: feature_group
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
@recordings_by_test = {}
|
49
|
+
@event_methods = Set.new
|
50
|
+
|
51
|
+
class << self
|
52
|
+
def init
|
53
|
+
warn 'Configuring AppMap recorder for Minitest'
|
54
|
+
|
55
|
+
FileUtils.mkdir_p APPMAP_OUTPUT_DIR
|
56
|
+
end
|
57
|
+
|
58
|
+
def begin_test(test)
|
59
|
+
@recordings_by_test[test.object_id] = Recording.new(test)
|
60
|
+
end
|
61
|
+
|
62
|
+
def end_test(test)
|
63
|
+
recording = @recordings_by_test.delete(test.object_id)
|
64
|
+
return warn "No recording found for #{test}" unless recording
|
65
|
+
|
66
|
+
recording.finish
|
67
|
+
end
|
68
|
+
|
69
|
+
def config
|
70
|
+
@config or raise "AppMap is not configured"
|
71
|
+
end
|
72
|
+
|
73
|
+
def add_event_methods(event_methods)
|
74
|
+
@event_methods += event_methods
|
75
|
+
end
|
76
|
+
|
77
|
+
def save(example_name, class_map, events: nil, feature_name: nil, feature_group_name: nil, labels: nil)
|
78
|
+
metadata = AppMap::Minitest.metadata.tap do |m|
|
79
|
+
m[:name] = example_name
|
80
|
+
m[:app] = AppMap.configuration.name
|
81
|
+
m[:feature] = feature_name if feature_name
|
82
|
+
m[:feature_group] = feature_group_name if feature_group_name
|
83
|
+
m[:frameworks] ||= []
|
84
|
+
m[:frameworks] << {
|
85
|
+
name: 'minitest',
|
86
|
+
version: Gem.loaded_specs['minitest']&.version&.to_s
|
87
|
+
}
|
88
|
+
m[:recorder] = {
|
89
|
+
name: 'minitest'
|
90
|
+
}
|
91
|
+
end
|
92
|
+
|
93
|
+
appmap = {
|
94
|
+
version: AppMap::APPMAP_FORMAT_VERSION,
|
95
|
+
metadata: metadata,
|
96
|
+
classMap: class_map,
|
97
|
+
events: events
|
98
|
+
}.compact
|
99
|
+
fname = AppMap::Util.scenario_filename(example_name)
|
100
|
+
|
101
|
+
File.write(File.join(APPMAP_OUTPUT_DIR, fname), JSON.generate(appmap))
|
102
|
+
end
|
103
|
+
|
104
|
+
def print_inventory
|
105
|
+
class_map = AppMap.class_map(@event_methods)
|
106
|
+
save 'Inventory', class_map, labels: %w[inventory]
|
107
|
+
end
|
108
|
+
|
109
|
+
def enabled?
|
110
|
+
ENV['APPMAP'] == 'true'
|
111
|
+
end
|
112
|
+
|
113
|
+
def run
|
114
|
+
init
|
115
|
+
at_exit do
|
116
|
+
print_inventory
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
if AppMap::Minitest.enabled?
|
124
|
+
require 'appmap'
|
125
|
+
require 'minitest/test'
|
126
|
+
|
127
|
+
class ::Minitest::Test
|
128
|
+
alias run_without_hook run
|
129
|
+
|
130
|
+
def run
|
131
|
+
AppMap::Minitest.begin_test self
|
132
|
+
begin
|
133
|
+
run_without_hook
|
134
|
+
ensure
|
135
|
+
AppMap::Minitest.end_test self
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
AppMap::Minitest.run
|
141
|
+
end
|
@@ -20,7 +20,7 @@ module AppMap
|
|
20
20
|
attr_accessor :payload
|
21
21
|
|
22
22
|
def initialize(path, lineno, payload)
|
23
|
-
super AppMap::Event.next_id_counter, :call, HTTPServerRequest, :call, path, lineno,
|
23
|
+
super AppMap::Event.next_id_counter, :call, HTTPServerRequest, :call, path, lineno, Thread.current.object_id
|
24
24
|
|
25
25
|
self.payload = payload
|
26
26
|
end
|
@@ -60,7 +60,7 @@ module AppMap
|
|
60
60
|
attr_accessor :payload
|
61
61
|
|
62
62
|
def initialize(path, lineno, payload, parent_id, elapsed)
|
63
|
-
super AppMap::Event.next_id_counter, :return, HTTPServerResponse, :call, path, lineno,
|
63
|
+
super AppMap::Event.next_id_counter, :return, HTTPServerResponse, :call, path, lineno, Thread.current.object_id
|
64
64
|
|
65
65
|
self.payload = payload
|
66
66
|
self.parent_id = parent_id
|
@@ -9,7 +9,7 @@ module AppMap
|
|
9
9
|
attr_accessor :payload
|
10
10
|
|
11
11
|
def initialize(path, lineno, payload)
|
12
|
-
super AppMap::Event.next_id_counter, :call, SQLHandler, :call, path, lineno,
|
12
|
+
super AppMap::Event.next_id_counter, :call, SQLHandler, :call, path, lineno, Thread.current.object_id
|
13
13
|
|
14
14
|
self.payload = payload
|
15
15
|
end
|
@@ -30,7 +30,7 @@ module AppMap
|
|
30
30
|
|
31
31
|
class SQLReturn < AppMap::Event::MethodReturnIgnoreValue
|
32
32
|
def initialize(path, lineno, parent_id, elapsed)
|
33
|
-
super AppMap::Event.next_id_counter, :return, SQLHandler, :call, path, lineno,
|
33
|
+
super AppMap::Event.next_id_counter, :return, SQLHandler, :call, path, lineno, Thread.current.object_id
|
34
34
|
|
35
35
|
self.parent_id = parent_id
|
36
36
|
self.elapsed = elapsed
|
data/lib/appmap/railtie.rb
CHANGED
@@ -5,8 +5,8 @@ module AppMap
|
|
5
5
|
class Railtie < ::Rails::Railtie
|
6
6
|
config.appmap = ActiveSupport::OrderedOptions.new
|
7
7
|
|
8
|
-
initializer 'appmap.init' do |_| #
|
9
|
-
|
8
|
+
initializer 'appmap.init' do |_| # params: app
|
9
|
+
require 'appmap'
|
10
10
|
end
|
11
11
|
|
12
12
|
# appmap.subscribe subscribes to ActiveSupport Notifications so that they can be recorded as
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'appmap'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
tracer = AppMap.tracing.trace
|
7
|
+
|
8
|
+
at_exit do
|
9
|
+
AppMap.tracing.delete(tracer)
|
10
|
+
|
11
|
+
events = [].tap do |event_list|
|
12
|
+
event_list << tracer.next_event.to_h while tracer.event?
|
13
|
+
end
|
14
|
+
|
15
|
+
metadata = AppMap.detect_metadata
|
16
|
+
metadata[:recorder] = {
|
17
|
+
name: 'record_process'
|
18
|
+
}
|
19
|
+
|
20
|
+
appmap = {
|
21
|
+
'version' => AppMap::APPMAP_FORMAT_VERSION,
|
22
|
+
'metadata' => metadata,
|
23
|
+
'classMap' => AppMap.class_map(tracer.event_methods),
|
24
|
+
'events' => events
|
25
|
+
}
|
26
|
+
File.write 'appmap.json', JSON.generate(appmap)
|
27
|
+
end
|
data/lib/appmap/rspec.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'appmap/util'
|
4
|
+
|
3
5
|
module AppMap
|
4
6
|
# Integration of AppMap with RSpec. When enabled with APPMAP=true, the AppMap tracer will
|
5
7
|
# be activated around each scenario which has the metadata key `:appmap`.
|
@@ -8,10 +10,7 @@ module AppMap
|
|
8
10
|
LOG = false
|
9
11
|
|
10
12
|
def self.metadata
|
11
|
-
|
12
|
-
@metadata ||= AppMap::Command::Record.detect_metadata
|
13
|
-
@metadata.freeze
|
14
|
-
@metadata.dup
|
13
|
+
AppMap.detect_metadata
|
15
14
|
end
|
16
15
|
|
17
16
|
module FeatureAnnotations
|
@@ -107,7 +106,17 @@ module AppMap
|
|
107
106
|
|
108
107
|
def parent
|
109
108
|
# An example group always has a parent; but it might be 'self'...
|
110
|
-
|
109
|
+
|
110
|
+
# DEPRECATION WARNING: `Module#parent` has been renamed to `module_parent`. `parent` is deprecated and will be
|
111
|
+
# removed in Rails 6.1. (called from parent at /Users/kgilpin/source/appland/appmap-ruby/lib/appmap/rspec.rb:110)
|
112
|
+
example_group_parent = \
|
113
|
+
if example_group.respond_to?(:module_parent)
|
114
|
+
example_group.module_parent
|
115
|
+
else
|
116
|
+
example_group.parent
|
117
|
+
end
|
118
|
+
|
119
|
+
example_group_parent != example_group ? ScopeExampleGroup.new(example_group_parent) : nil
|
111
120
|
end
|
112
121
|
end
|
113
122
|
|
@@ -129,7 +138,7 @@ module AppMap
|
|
129
138
|
|
130
139
|
AppMap::RSpec.add_event_methods @trace.event_methods
|
131
140
|
|
132
|
-
class_map = AppMap.class_map(
|
141
|
+
class_map = AppMap.class_map(@trace.event_methods)
|
133
142
|
|
134
143
|
description = []
|
135
144
|
scope = ScopeExample.new(example)
|
@@ -180,7 +189,6 @@ module AppMap
|
|
180
189
|
end
|
181
190
|
|
182
191
|
@recordings_by_example = {}
|
183
|
-
@config = nil
|
184
192
|
@event_methods = Set.new
|
185
193
|
|
186
194
|
class << self
|
@@ -188,10 +196,6 @@ module AppMap
|
|
188
196
|
warn 'Configuring AppMap recorder for RSpec'
|
189
197
|
|
190
198
|
FileUtils.mkdir_p APPMAP_OUTPUT_DIR
|
191
|
-
|
192
|
-
require 'appmap/hook'
|
193
|
-
@config = AppMap.configure
|
194
|
-
AppMap::Hook.hook(@config)
|
195
199
|
end
|
196
200
|
|
197
201
|
def begin_spec(example)
|
@@ -214,9 +218,9 @@ module AppMap
|
|
214
218
|
end
|
215
219
|
|
216
220
|
def save(example_name, class_map, events: nil, feature_name: nil, feature_group_name: nil, labels: nil)
|
217
|
-
metadata = RSpec.metadata.
|
221
|
+
metadata = AppMap::RSpec.metadata.tap do |m|
|
218
222
|
m[:name] = example_name
|
219
|
-
m[:app] =
|
223
|
+
m[:app] = AppMap.configuration.name
|
220
224
|
m[:feature] = feature_name if feature_name
|
221
225
|
m[:feature_group] = feature_group_name if feature_group_name
|
222
226
|
m[:labels] = labels if labels
|
@@ -236,13 +240,13 @@ module AppMap
|
|
236
240
|
classMap: class_map,
|
237
241
|
events: events
|
238
242
|
}.compact
|
239
|
-
fname =
|
243
|
+
fname = AppMap::Util.scenario_filename(example_name)
|
240
244
|
|
241
|
-
File.write(File.join(APPMAP_OUTPUT_DIR,
|
245
|
+
File.write(File.join(APPMAP_OUTPUT_DIR, fname), JSON.generate(appmap))
|
242
246
|
end
|
243
247
|
|
244
248
|
def print_inventory
|
245
|
-
class_map = AppMap.class_map(@
|
249
|
+
class_map = AppMap.class_map(@event_methods)
|
246
250
|
save 'Inventory', class_map, labels: %w[inventory]
|
247
251
|
end
|
248
252
|
|
@@ -256,28 +260,6 @@ module AppMap
|
|
256
260
|
print_inventory
|
257
261
|
end
|
258
262
|
end
|
259
|
-
|
260
|
-
private
|
261
|
-
|
262
|
-
# Cribbed from v5 version of ActiveSupport:Inflector#parameterize:
|
263
|
-
# https://github.com/rails/rails/blob/v5.2.4/activesupport/lib/active_support/inflector/transliterate.rb#L92
|
264
|
-
def sanitize_filename(fname, separator: '_')
|
265
|
-
# Replace accented chars with their ASCII equivalents.
|
266
|
-
fname = fname.encode('utf-8', invalid: :replace, undef: :replace, replace: '_')
|
267
|
-
|
268
|
-
# Turn unwanted chars into the separator.
|
269
|
-
fname.gsub!(/[^a-z0-9\-_]+/i, separator)
|
270
|
-
|
271
|
-
re_sep = Regexp.escape(separator)
|
272
|
-
re_duplicate_separator = /#{re_sep}{2,}/
|
273
|
-
re_leading_trailing_separator = /^#{re_sep}|#{re_sep}$/i
|
274
|
-
|
275
|
-
# No more than one of the separator in a row.
|
276
|
-
fname.gsub!(re_duplicate_separator, separator)
|
277
|
-
|
278
|
-
# Finally, Remove leading/trailing separator.
|
279
|
-
fname.gsub(re_leading_trailing_separator, '')
|
280
|
-
end
|
281
263
|
end
|
282
264
|
end
|
283
265
|
end
|
data/lib/appmap/trace.rb
CHANGED
@@ -2,38 +2,46 @@
|
|
2
2
|
|
3
3
|
module AppMap
|
4
4
|
module Trace
|
5
|
-
ScopedMethod
|
5
|
+
class ScopedMethod < SimpleDelegator
|
6
|
+
attr_reader :defined_class, :static
|
7
|
+
|
8
|
+
def initialize(defined_class, method, static)
|
9
|
+
@defined_class = defined_class
|
10
|
+
@static = static
|
11
|
+
super(method)
|
12
|
+
end
|
13
|
+
end
|
6
14
|
|
7
|
-
class
|
15
|
+
class Tracing
|
8
16
|
def initialize
|
9
|
-
@
|
17
|
+
@Tracing = []
|
10
18
|
end
|
11
19
|
|
12
20
|
def empty?
|
13
|
-
@
|
21
|
+
@Tracing.empty?
|
14
22
|
end
|
15
23
|
|
16
24
|
def trace(enable: true)
|
17
25
|
Tracer.new.tap do |tracer|
|
18
|
-
@
|
26
|
+
@Tracing << tracer
|
19
27
|
tracer.enable if enable
|
20
28
|
end
|
21
|
-
end
|
29
|
+
end
|
22
30
|
|
23
31
|
def enabled?
|
24
|
-
@
|
32
|
+
@Tracing.any?(&:enabled?)
|
25
33
|
end
|
26
34
|
|
27
35
|
def record_event(event, defined_class: nil, method: nil)
|
28
|
-
@
|
36
|
+
@Tracing.each do |tracer|
|
29
37
|
tracer.record_event(event, defined_class: defined_class, method: method)
|
30
38
|
end
|
31
39
|
end
|
32
40
|
|
33
41
|
def delete(tracer)
|
34
|
-
return unless @
|
42
|
+
return unless @Tracing.member?(tracer)
|
35
43
|
|
36
|
-
@
|
44
|
+
@Tracing.delete(tracer)
|
37
45
|
tracer.disable
|
38
46
|
end
|
39
47
|
end
|
@@ -67,7 +75,7 @@ module AppMap
|
|
67
75
|
return unless @enabled
|
68
76
|
|
69
77
|
@events << event
|
70
|
-
@methods << Trace::ScopedMethod.new(defined_class, method) if defined_class && method
|
78
|
+
@methods << Trace::ScopedMethod.new(defined_class, method, event.static) if (defined_class && method && event.event == :call)
|
71
79
|
end
|
72
80
|
|
73
81
|
# Gets a unique list of the methods that were invoked by the program.
|