appmap 0.25.0 → 0.28.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 +33 -0
- data/README.md +123 -39
- data/exe/appmap +3 -57
- data/lib/appmap.rb +51 -32
- data/lib/appmap/command/record.rb +2 -61
- data/lib/appmap/cucumber.rb +89 -0
- data/lib/appmap/event.rb +1 -1
- data/lib/appmap/hook.rb +7 -1
- data/lib/appmap/metadata.rb +62 -0
- data/lib/appmap/middleware/remote_recording.rb +2 -7
- data/lib/appmap/rails/sql_handler.rb +0 -5
- data/lib/appmap/railtie.rb +2 -2
- data/lib/appmap/rspec.rb +20 -38
- data/lib/appmap/trace.rb +9 -9
- data/lib/appmap/util.rb +40 -0
- data/lib/appmap/version.rb +1 -1
- 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 +21 -3
- data/spec/rails_spec_helper.rb +2 -0
- data/spec/rspec_feature_metadata_spec.rb +2 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/util_spec.rb +21 -0
- data/test/cli_test.rb +0 -13
- 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/rspec_recorder/Gemfile +1 -1
- data/test/fixtures/rspec_recorder/spec/decorated_hello_spec.rb +12 -0
- data/test/rspec_test.rb +5 -0
- metadata +26 -3
- data/lib/appmap/command/upload.rb +0 -101
@@ -5,66 +5,7 @@ module AppMap
|
|
5
5
|
RecordStruct = Struct.new(:config, :program)
|
6
6
|
|
7
7
|
class Record < RecordStruct
|
8
|
-
class << self
|
9
|
-
# Builds a Hash of metadata which can be detected by inspecting the system.
|
10
|
-
def detect_metadata
|
11
|
-
{
|
12
|
-
language: {
|
13
|
-
name: 'ruby',
|
14
|
-
engine: RUBY_ENGINE,
|
15
|
-
version: RUBY_VERSION
|
16
|
-
},
|
17
|
-
client: {
|
18
|
-
name: 'appmap',
|
19
|
-
url: AppMap::URL,
|
20
|
-
version: AppMap::VERSION
|
21
|
-
}
|
22
|
-
}.tap do |m|
|
23
|
-
if defined?(::Rails)
|
24
|
-
m[:frameworks] ||= []
|
25
|
-
m[:frameworks] << {
|
26
|
-
name: 'rails',
|
27
|
-
version: ::Rails.version
|
28
|
-
}
|
29
|
-
end
|
30
|
-
m[:git] = git_metadata if git_available
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
protected
|
35
|
-
|
36
|
-
def git_available
|
37
|
-
@git_available = system('git status 2>&1 > /dev/null') if @git_available.nil?
|
38
|
-
end
|
39
|
-
|
40
|
-
def git_metadata
|
41
|
-
git_repo = `git config --get remote.origin.url`.strip
|
42
|
-
git_branch = `git rev-parse --abbrev-ref HEAD`.strip
|
43
|
-
git_sha = `git rev-parse HEAD`.strip
|
44
|
-
git_status = `git status -s`.split("\n").map(&:strip)
|
45
|
-
git_last_annotated_tag = `git describe --abbrev=0 2>/dev/null`.strip
|
46
|
-
git_last_annotated_tag = nil if git_last_annotated_tag.blank?
|
47
|
-
git_last_tag = `git describe --abbrev=0 --tags 2>/dev/null`.strip
|
48
|
-
git_last_tag = nil if git_last_tag.blank?
|
49
|
-
git_commits_since_last_annotated_tag = `git describe`.strip =~ /-(\d+)-(\w+)$/[1] rescue 0 if git_last_annotated_tag
|
50
|
-
git_commits_since_last_tag = `git describe --tags`.strip =~ /-(\d+)-(\w+)$/[1] rescue 0 if git_last_tag
|
51
|
-
|
52
|
-
{
|
53
|
-
repository: git_repo,
|
54
|
-
branch: git_branch,
|
55
|
-
commit: git_sha,
|
56
|
-
status: git_status,
|
57
|
-
git_last_annotated_tag: git_last_annotated_tag,
|
58
|
-
git_last_tag: git_last_tag,
|
59
|
-
git_commits_since_last_annotated_tag: git_commits_since_last_annotated_tag,
|
60
|
-
git_commits_since_last_tag: git_commits_since_last_tag
|
61
|
-
}
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
8
|
def perform(&block)
|
66
|
-
AppMap::Hook.hook(config)
|
67
|
-
|
68
9
|
tracer = AppMap.tracing.trace
|
69
10
|
|
70
11
|
events = []
|
@@ -85,8 +26,8 @@ module AppMap
|
|
85
26
|
quit = true
|
86
27
|
event_thread.join
|
87
28
|
yield AppMap::APPMAP_FORMAT_VERSION,
|
88
|
-
|
89
|
-
AppMap.class_map(
|
29
|
+
AppMap.detect_metadata,
|
30
|
+
AppMap.class_map(tracer.event_methods),
|
90
31
|
events
|
91
32
|
end
|
92
33
|
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'appmap/util'
|
4
|
+
|
5
|
+
module AppMap
|
6
|
+
module Cucumber
|
7
|
+
ScenarioAttributes = Struct.new(:name, :feature, :feature_group)
|
8
|
+
|
9
|
+
ProviderStruct = Struct.new(:scenario) do
|
10
|
+
def feature_group
|
11
|
+
# e.g. <Cucumber::Core::Ast::Location::Precise: cucumber/api/features/authenticate.feature:1>
|
12
|
+
feature_path.split('/').last.split('.')[0]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# ProviderBefore4 provides scenario name, feature name, and feature group name for Cucumber
|
17
|
+
# versions before 4.0.
|
18
|
+
class ProviderBefore4 < ProviderStruct
|
19
|
+
def attributes
|
20
|
+
ScenarioAttributes.new(scenario.name, scenario.feature.name, feature_group)
|
21
|
+
end
|
22
|
+
|
23
|
+
def feature_path
|
24
|
+
scenario.feature.location.to_s
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Provider4 provides scenario name, feature name, and feature group name for Cucumber
|
29
|
+
# versions 4.0 and later.
|
30
|
+
class Provider4 < ProviderStruct
|
31
|
+
def attributes
|
32
|
+
ScenarioAttributes.new(scenario.name, scenario.name.split(' ')[0..1].join(' '), feature_group)
|
33
|
+
end
|
34
|
+
|
35
|
+
def feature_path
|
36
|
+
scenario.location.file
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class << self
|
41
|
+
def write_scenario(scenario, appmap)
|
42
|
+
appmap['metadata'] = update_metadata(scenario, appmap['metadata'])
|
43
|
+
scenario_filename = AppMap::Util.scenario_filename(appmap['metadata']['name'])
|
44
|
+
|
45
|
+
FileUtils.mkdir_p 'tmp/appmap/cucumber'
|
46
|
+
File.write(File.join('tmp/appmap/cucumber', scenario_filename), JSON.generate(appmap))
|
47
|
+
end
|
48
|
+
|
49
|
+
def enabled?
|
50
|
+
ENV['APPMAP'] == 'true'
|
51
|
+
end
|
52
|
+
|
53
|
+
protected
|
54
|
+
|
55
|
+
def cucumber_version
|
56
|
+
Gem.loaded_specs['cucumber']&.version&.to_s
|
57
|
+
end
|
58
|
+
|
59
|
+
def provider(scenario)
|
60
|
+
major, = cucumber_version.split('.').map(&:to_i)
|
61
|
+
if major < 4
|
62
|
+
ProviderBefore4
|
63
|
+
else
|
64
|
+
Provider4
|
65
|
+
end.new(scenario)
|
66
|
+
end
|
67
|
+
|
68
|
+
def update_metadata(scenario, base_metadata)
|
69
|
+
attributes = provider(scenario).attributes
|
70
|
+
|
71
|
+
base_metadata.tap do |m|
|
72
|
+
m['name'] = attributes.name
|
73
|
+
m['feature'] = attributes.feature
|
74
|
+
m['feature_group'] = attributes.feature_group
|
75
|
+
m['labels'] ||= []
|
76
|
+
m['labels'] += (scenario.tags&.map(&:name) || [])
|
77
|
+
m['frameworks'] ||= []
|
78
|
+
m['frameworks'] << {
|
79
|
+
'name' => 'cucumber',
|
80
|
+
'version' => Gem.loaded_specs['cucumber']&.version&.to_s
|
81
|
+
}
|
82
|
+
m['recorder'] = {
|
83
|
+
'name' => 'cucumber'
|
84
|
+
}
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
data/lib/appmap/event.rb
CHANGED
@@ -139,7 +139,7 @@ module AppMap
|
|
139
139
|
next_exception = exception
|
140
140
|
exceptions = []
|
141
141
|
while next_exception
|
142
|
-
exception_backtrace = next_exception.backtrace_locations[0
|
142
|
+
exception_backtrace = next_exception.backtrace_locations.try(:[], 0)
|
143
143
|
exceptions << {
|
144
144
|
class: next_exception.class.name,
|
145
145
|
message: next_exception.message,
|
data/lib/appmap/hook.rb
CHANGED
@@ -115,7 +115,12 @@ module AppMap
|
|
115
115
|
[ method.owner.name, '#' ]
|
116
116
|
end
|
117
117
|
|
118
|
-
|
118
|
+
method_display_name = "#{defined_class}#{method_symbol}#{method.name}"
|
119
|
+
# Don't try and trace the tracing method or there will be a stack overflow
|
120
|
+
# in the defined hook method.
|
121
|
+
next if method_display_name == "AppMap.tracing"
|
122
|
+
|
123
|
+
warn "AppMap: Hooking #{method_display_name}" if LOG
|
119
124
|
|
120
125
|
cls.define_method method_id do |*args, &block|
|
121
126
|
base_method = method.bind(self).to_proc
|
@@ -133,6 +138,7 @@ module AppMap
|
|
133
138
|
return_value = base_method.call(*args, &block)
|
134
139
|
rescue
|
135
140
|
exception = $ERROR_INFO
|
141
|
+
raise
|
136
142
|
ensure
|
137
143
|
with_disabled_hook.call do
|
138
144
|
after_hook.call(call_event, defined_class, method, start_time, return_value, exception)
|
@@ -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)
|
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,13 +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
|
-
require 'appmap/command/upload'
|
10
8
|
require 'json'
|
11
9
|
|
12
10
|
@app = app
|
13
|
-
@config = AppMap.configure
|
14
|
-
AppMap::Hook.hook(@config)
|
15
11
|
end
|
16
12
|
|
17
13
|
def event_loop
|
@@ -64,15 +60,14 @@ module AppMap
|
|
64
60
|
@events.delete_if(&is_control_command_event)
|
65
61
|
@events.delete_if(&is_return_from_control_command_event)
|
66
62
|
|
67
|
-
|
68
|
-
metadata = AppMap::Command::Record.detect_metadata
|
63
|
+
metadata = AppMap.detect_metadata
|
69
64
|
metadata[:recorder] = {
|
70
65
|
name: 'remote_recording'
|
71
66
|
}
|
72
67
|
|
73
68
|
response = JSON.generate \
|
74
69
|
version: AppMap::APPMAP_FORMAT_VERSION,
|
75
|
-
classMap: AppMap.class_map(
|
70
|
+
classMap: AppMap.class_map(tracer.event_methods),
|
76
71
|
metadata: metadata,
|
77
72
|
events: @events
|
78
73
|
|
@@ -102,9 +102,6 @@ module AppMap
|
|
102
102
|
Thread.current[reentry_key] = true
|
103
103
|
begin
|
104
104
|
sql = payload[:sql].strip
|
105
|
-
sql_upper = sql.upcase
|
106
|
-
|
107
|
-
return unless WHITELIST.find { |keyword| sql_upper.index(keyword) == 0 }
|
108
105
|
|
109
106
|
# Detect whether a function call within a specified filename is present in the call stack.
|
110
107
|
find_in_backtrace = lambda do |file_name, function_name = nil|
|
@@ -143,8 +140,6 @@ module AppMap
|
|
143
140
|
Thread.current[reentry_key] = nil
|
144
141
|
end
|
145
142
|
end
|
146
|
-
|
147
|
-
WHITELIST = %w[SELECT INSERT UPDATE DELETE].freeze
|
148
143
|
end
|
149
144
|
end
|
150
145
|
end
|
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
|
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 = 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
@@ -4,36 +4,36 @@ module AppMap
|
|
4
4
|
module Trace
|
5
5
|
ScopedMethod = Struct.new(:defined_class, :method)
|
6
6
|
|
7
|
-
class
|
7
|
+
class Tracing
|
8
8
|
def initialize
|
9
|
-
@
|
9
|
+
@Tracing = []
|
10
10
|
end
|
11
11
|
|
12
12
|
def empty?
|
13
|
-
@
|
13
|
+
@Tracing.empty?
|
14
14
|
end
|
15
15
|
|
16
16
|
def trace(enable: true)
|
17
17
|
Tracer.new.tap do |tracer|
|
18
|
-
@
|
18
|
+
@Tracing << tracer
|
19
19
|
tracer.enable if enable
|
20
20
|
end
|
21
|
-
end
|
21
|
+
end
|
22
22
|
|
23
23
|
def enabled?
|
24
|
-
@
|
24
|
+
@Tracing.any?(&:enabled?)
|
25
25
|
end
|
26
26
|
|
27
27
|
def record_event(event, defined_class: nil, method: nil)
|
28
|
-
@
|
28
|
+
@Tracing.each do |tracer|
|
29
29
|
tracer.record_event(event, defined_class: defined_class, method: method)
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
33
|
def delete(tracer)
|
34
|
-
return unless @
|
34
|
+
return unless @Tracing.member?(tracer)
|
35
35
|
|
36
|
-
@
|
36
|
+
@Tracing.delete(tracer)
|
37
37
|
tracer.disable
|
38
38
|
end
|
39
39
|
end
|