appmap 0.94.1 → 0.95.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 +2 -0
- data/.nvmrc +1 -0
- data/.ruby-version +1 -0
- data/.rufo +2 -0
- data/CHANGELOG.md +17 -0
- data/lib/appmap/builtin_hooks/{activesupport.yml → active_support.yml} +1 -1
- data/lib/appmap/builtin_hooks/ruby.yml +2 -2
- data/lib/appmap/config.rb +6 -1
- data/lib/appmap/gem_hooks/rails.yml +1 -1
- data/lib/appmap/gem_hooks/railties.yml +1 -1
- data/lib/appmap/hook/method.rb +7 -8
- data/lib/appmap/hook.rb +125 -113
- data/lib/appmap/hook_log.rb +99 -0
- data/lib/appmap/version.rb +1 -1
- data/yarn.lock +1206 -417
- metadata +7 -4
- data/lib/appmap/gem_hooks/activerecord.yml +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a3f036b61b1750e2820f676694a15af9461404dc9b8f048add0b9b7291dd1d4a
|
4
|
+
data.tar.gz: f40f6587ecbf21c250952b1ecfc51349d6ad3cf53276d6cf30d9a97f859295b2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bd45853f98e82f90b6885b615931f73b125a5194041221c0bf9f21b41ab1f2285489ef3b7e1915905b41e434e65d607eebdf232d53a6bc1e1b75f516f73d2222
|
7
|
+
data.tar.gz: 3465e8521239b8eadc1145e06847bb454a1f6b43ef0adf6ed50f8d2fb6eccb63ac79a86b913628db7344b10c8b68980dd6c3aa5ac9741eac4bfef6b39d109a76
|
data/.gitignore
CHANGED
data/.nvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
14
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
3.0.2
|
data/.rufo
ADDED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,20 @@
|
|
1
|
+
# [0.95.0](https://github.com/getappmap/appmap-ruby/compare/v0.94.1...v0.95.0) (2022-12-15)
|
2
|
+
|
3
|
+
|
4
|
+
### Bug Fixes
|
5
|
+
|
6
|
+
* Disable active_record hooks ([239986d](https://github.com/getappmap/appmap-ruby/commit/239986deded12e65384b441033180c30a3ffe698))
|
7
|
+
* Fix Array#pack hook ([2a8b2ed](https://github.com/getappmap/appmap-ruby/commit/2a8b2ed4d9fb047213e6a3fd427d846c5d312e2f))
|
8
|
+
* Fix name of rails7 test database ([6581b65](https://github.com/getappmap/appmap-ruby/commit/6581b65c088ee8415fd150d11c4ab6793173f0e2))
|
9
|
+
* Typo in label configuration ([999b25b](https://github.com/getappmap/appmap-ruby/commit/999b25b75057a7f6061cfbc9cdc04616f5aeb998))
|
10
|
+
|
11
|
+
|
12
|
+
### Features
|
13
|
+
|
14
|
+
* Enable deserialize.safe labels ([62be78a](https://github.com/getappmap/appmap-ruby/commit/62be78a0502d83c9b5a2b7d97abd17d144bd41c5))
|
15
|
+
* Enhance the hook log a lot ([c93d91c](https://github.com/getappmap/appmap-ruby/commit/c93d91c5be86b9195e14ef40741600c633638b40))
|
16
|
+
* Enhancing hook logging and profiling ([01dbe4b](https://github.com/getappmap/appmap-ruby/commit/01dbe4bb973b71fea0885f55d17b80d6b6b8fb6e))
|
17
|
+
|
1
18
|
## [0.94.1](https://github.com/getappmap/appmap-ruby/compare/v0.94.0...v0.94.1) (2022-11-23)
|
2
19
|
|
3
20
|
|
@@ -19,6 +19,6 @@
|
|
19
19
|
- method: ActiveSupport::MessageEncryptor#encrypt_and_sign
|
20
20
|
require_name: active_support/message_encryptor
|
21
21
|
force: true
|
22
|
-
- method: ActiveSupport::MessageEncryptor#
|
22
|
+
- method: ActiveSupport::MessageEncryptor#decrypt_and_verify
|
23
23
|
require_name: active_support/message_encryptor
|
24
24
|
force: true
|
data/lib/appmap/config.rb
CHANGED
@@ -8,6 +8,7 @@ require 'appmap/handler'
|
|
8
8
|
require 'appmap/service/guesser'
|
9
9
|
require 'appmap/swagger/configuration'
|
10
10
|
require 'appmap/depends/configuration'
|
11
|
+
require_relative './hook_log'
|
11
12
|
|
12
13
|
module AppMap
|
13
14
|
class Config
|
@@ -499,7 +500,11 @@ module AppMap
|
|
499
500
|
|
500
501
|
def never_hook?(cls, method)
|
501
502
|
_, separator, = ::AppMap::Hook.qualify_method_name(method)
|
502
|
-
|
503
|
+
if exclude.member?(cls.name) || exclude.member?([ cls.name, separator, method.name ].join)
|
504
|
+
HookLog.log "Hooking of #{method} disabled by configuration" if HookLog.enabled?
|
505
|
+
return true
|
506
|
+
end
|
507
|
+
false
|
503
508
|
end
|
504
509
|
end
|
505
510
|
end
|
@@ -1,2 +1,2 @@
|
|
1
1
|
- method: Rails::Application#config_for
|
2
|
-
|
2
|
+
label: deserialize.safe
|
@@ -1,2 +1,2 @@
|
|
1
1
|
- method: Rails::Application::Configuration#database_configuration
|
2
|
-
|
2
|
+
label: deserialize.safe
|
data/lib/appmap/hook/method.rb
CHANGED
@@ -38,13 +38,13 @@ module AppMap
|
|
38
38
|
end
|
39
39
|
|
40
40
|
def activate
|
41
|
-
if
|
41
|
+
if HookLog.enabled?
|
42
42
|
msg = if method_display_name
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
43
|
+
"#{method_display_name}"
|
44
|
+
else
|
45
|
+
"#{hook_method.name} (class resolution deferred)"
|
46
|
+
end
|
47
|
+
HookLog.log "Hooking #{msg} at line #{(hook_method.source_location || []).join(':')}"
|
48
48
|
end
|
49
49
|
|
50
50
|
hook_method_parameters = hook_method.parameters.dup.freeze
|
@@ -65,8 +65,7 @@ module AppMap
|
|
65
65
|
protected
|
66
66
|
|
67
67
|
def defining_class(hook_class)
|
68
|
-
cls =
|
69
|
-
if RUBY_MAJOR_VERSION == 2 && RUBY_MINOR_VERSION <= 5
|
68
|
+
cls = if RUBY_MAJOR_VERSION == 2 && RUBY_MINOR_VERSION <= 5
|
70
69
|
hook_class
|
71
70
|
.ancestors
|
72
71
|
.select { |cls| cls.method_defined?(hook_method.name) }
|
data/lib/appmap/hook.rb
CHANGED
@@ -1,17 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'English'
|
4
|
+
require_relative './hook_log'
|
4
5
|
|
5
6
|
module AppMap
|
6
7
|
class Hook
|
7
|
-
LOG = (ENV['APPMAP_DEBUG'] == 'true' || ENV['DEBUG'] == 'true')
|
8
|
-
LOG_HOOK = (ENV['DEBUG_HOOK'] == 'true')
|
9
|
-
|
10
8
|
OBJECT_INSTANCE_METHODS = %i[! != !~ <=> == === =~ __id__ __send__ class clone define_singleton_method display dup
|
11
9
|
enum_for eql? equal? extend freeze frozen? hash inspect instance_eval instance_exec instance_of? instance_variable_defined? instance_variable_get instance_variable_set instance_variables is_a? itself kind_of? method methods nil? object_id private_methods protected_methods public_method public_methods public_send remove_instance_variable respond_to? send singleton_class singleton_method singleton_methods taint tainted? tap then to_enum to_s to_h to_a trust untaint untrust untrusted? yield_self].freeze
|
12
10
|
OBJECT_STATIC_METHODS = %i[! != !~ < <= <=> == === =~ > >= __id__ __send__ alias_method allocate ancestors attr
|
13
11
|
attr_accessor attr_reader attr_writer autoload autoload? class class_eval class_exec class_variable_defined? class_variable_get class_variable_set class_variables clone const_defined? const_get const_missing const_set constants define_method define_singleton_method deprecate_constant display dup enum_for eql? equal? extend freeze frozen? hash include include? included_modules inspect instance_eval instance_exec instance_method instance_methods instance_of? instance_variable_defined? instance_variable_get instance_variable_set instance_variables is_a? itself kind_of? method method_defined? methods module_eval module_exec name new nil? object_id prepend private_class_method private_constant private_instance_methods private_method_defined? private_methods protected_instance_methods protected_method_defined? protected_methods public_class_method public_constant public_instance_method public_instance_methods public_method public_method_defined? public_methods public_send remove_class_variable remove_instance_variable remove_method respond_to? send singleton_class singleton_class? singleton_method singleton_methods superclass taint tainted? tap then to_enum to_s trust undef_method untaint untrust untrusted? yield_self].freeze
|
14
|
-
SLOW_PACKAGE_THRESHOLD = 0.
|
12
|
+
SLOW_PACKAGE_THRESHOLD = 0.001
|
15
13
|
|
16
14
|
@unbound_method_arity = ::UnboundMethod.instance_method(:arity)
|
17
15
|
@method_arity = ::Method.instance_method(:arity)
|
@@ -21,7 +19,7 @@ module AppMap
|
|
21
19
|
Mutex.new.synchronize do
|
22
20
|
@hook_builtins = true if @hook_builtins.nil?
|
23
21
|
|
24
|
-
|
22
|
+
next false unless @hook_builtins
|
25
23
|
|
26
24
|
@hook_builtins = false
|
27
25
|
true
|
@@ -41,9 +39,9 @@ module AppMap
|
|
41
39
|
def qualify_method_name(method)
|
42
40
|
if method.owner.singleton_class?
|
43
41
|
class_name = singleton_method_owner_name(method)
|
44
|
-
[
|
42
|
+
[class_name, '.', method.name]
|
45
43
|
else
|
46
|
-
[
|
44
|
+
[method.owner.name, '#', method.name]
|
47
45
|
end
|
48
46
|
end
|
49
47
|
end
|
@@ -69,19 +67,23 @@ module AppMap
|
|
69
67
|
@slow_packages = Set.new
|
70
68
|
|
71
69
|
if ENV['APPMAP_PROFILE_HOOK'] == 'true'
|
70
|
+
dump_times = lambda do
|
71
|
+
@module_load_times
|
72
|
+
.keys
|
73
|
+
.select { |key| !@slow_packages.member?(key) }
|
74
|
+
.each do |key|
|
75
|
+
elapsed = @module_load_times[key]
|
76
|
+
if elapsed >= SLOW_PACKAGE_THRESHOLD
|
77
|
+
@slow_packages.add(key)
|
78
|
+
warn "AppMap: Package #{key} took #{@module_load_times[key]} seconds to hook"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
at_exit &dump_times
|
72
84
|
Thread.new do
|
73
|
-
sleep 1
|
74
85
|
while true
|
75
|
-
|
76
|
-
.keys
|
77
|
-
.select { |key| !@slow_packages.member?(key) }
|
78
|
-
.each do |key|
|
79
|
-
elapsed = @module_load_times[key]
|
80
|
-
if elapsed >= SLOW_PACKAGE_THRESHOLD
|
81
|
-
@slow_packages.add(key)
|
82
|
-
warn "AppMap: Package #{key} took #{@module_load_times[key]} seconds to hook"
|
83
|
-
end
|
84
|
-
end
|
86
|
+
dump_times.call
|
85
87
|
sleep 5
|
86
88
|
end
|
87
89
|
end
|
@@ -99,45 +101,51 @@ module AppMap
|
|
99
101
|
hook_loaded_code = lambda do |hooks_by_class, builtin|
|
100
102
|
hooks_by_class.each do |class_name, hooks|
|
101
103
|
Array(hooks).each do |hook|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
104
|
+
HookLog.builtin class_name do
|
105
|
+
if builtin && hook.package.require_name && hook.package.require_name != 'ruby'
|
106
|
+
begin
|
107
|
+
require hook.package.require_name
|
108
|
+
rescue
|
109
|
+
HookLog.load_error hook.package.require_name, "Unable to require #{hook.package.require_name}: #{$!}" if HookLog.enabled?
|
110
|
+
next
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
111
114
|
begin
|
112
115
|
base_cls = Object.const_get class_name
|
113
116
|
rescue NameError
|
117
|
+
HookLog.load_error class_name, "Class #{class_name} not found in global scope" if HookLog.enabled?
|
114
118
|
next
|
115
119
|
end
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
methods << [
|
134
|
-
methods << [
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
methods.
|
120
|
+
|
121
|
+
Array(hook.method_names).each do |method_name|
|
122
|
+
method_name = method_name.to_sym
|
123
|
+
|
124
|
+
hook_method = lambda do |entry|
|
125
|
+
cls, method = entry
|
126
|
+
next if config.never_hook?(cls, method)
|
127
|
+
|
128
|
+
hook.package.handler_class.new(hook.package, cls, method).activate
|
129
|
+
end
|
130
|
+
|
131
|
+
methods = []
|
132
|
+
# irb(main):001:0> Kernel.public_instance_method(:system)
|
133
|
+
# (irb):1:in `public_instance_method': method `system' for module `Kernel' is private (NameError)
|
134
|
+
if base_cls == Kernel
|
135
|
+
methods << [base_cls, base_cls.instance_method(method_name)] rescue nil
|
136
|
+
end
|
137
|
+
methods << [base_cls, base_cls.public_instance_method(method_name)] rescue nil
|
138
|
+
methods << [base_cls, base_cls.protected_instance_method(method_name)] rescue nil
|
139
|
+
if base_cls.respond_to?(:singleton_class)
|
140
|
+
methods << [base_cls.singleton_class, base_cls.singleton_class.public_instance_method(method_name)] rescue nil
|
141
|
+
methods << [base_cls.singleton_class, base_cls.singleton_class.protected_instance_method(method_name)] rescue nil
|
142
|
+
end
|
143
|
+
methods.compact!
|
144
|
+
if methods.empty?
|
145
|
+
HookLog.load_error [ base_cls.name, method_name ].join('[#.]'), "Method #{method_name} not found on #{base_cls.name}" if HookLog.enabled?
|
146
|
+
else
|
147
|
+
methods.each(&hook_method)
|
148
|
+
end
|
141
149
|
end
|
142
150
|
end
|
143
151
|
end
|
@@ -145,89 +153,93 @@ module AppMap
|
|
145
153
|
end
|
146
154
|
|
147
155
|
hook_loaded_code.(config.builtin_hooks, true)
|
148
|
-
hook_loaded_code.(config.gem_hooks, false)
|
149
156
|
end
|
150
157
|
|
151
158
|
protected
|
152
159
|
|
153
160
|
def trace_location(trace_point)
|
154
|
-
[
|
161
|
+
[trace_point.path, trace_point.lineno].join(':')
|
155
162
|
end
|
156
163
|
|
157
164
|
def trace_end(trace_point)
|
158
165
|
location = trace_location(trace_point)
|
159
|
-
warn "Class or module ends at location #{location}" if Hook::LOG || Hook::LOG_HOOK
|
160
166
|
return unless @trace_locations.add?(location)
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
end
|
169
|
-
|
170
|
-
cls = trace_point.self
|
171
|
-
|
172
|
-
instance_methods = cls.public_instance_methods(false) + cls.protected_instance_methods(false) - OBJECT_INSTANCE_METHODS
|
173
|
-
# NoMethodError: private method `singleton_class' called for Rack::MiniProfiler:Class
|
174
|
-
class_methods = begin
|
175
|
-
if cls.respond_to?(:singleton_class)
|
176
|
-
cls.singleton_class.public_instance_methods(false) + cls.singleton_class.protected_instance_methods(false) - instance_methods - OBJECT_STATIC_METHODS
|
177
|
-
else
|
178
|
-
[]
|
167
|
+
HookLog.on_load location do
|
168
|
+
path = trace_point.path
|
169
|
+
enabled = !@notrace_paths.member?(path) && config.path_enabled?(path)
|
170
|
+
unless enabled
|
171
|
+
HookLog.log 'Not hooking - path is not enabled' if HookLog.enabled?
|
172
|
+
@notrace_paths << path
|
173
|
+
next
|
179
174
|
end
|
180
|
-
rescue NameError
|
181
|
-
[]
|
182
|
-
end
|
183
175
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
176
|
+
cls = trace_point.self
|
177
|
+
|
178
|
+
instance_methods = cls.public_instance_methods(false) + cls.protected_instance_methods(false) - OBJECT_INSTANCE_METHODS
|
179
|
+
# NoMethodError: private method `singleton_class' called for Rack::MiniProfiler:Class
|
180
|
+
class_methods = begin
|
181
|
+
if cls.respond_to?(:singleton_class)
|
182
|
+
cls.singleton_class.public_instance_methods(false) + cls.singleton_class.protected_instance_methods(false) - instance_methods - OBJECT_STATIC_METHODS
|
183
|
+
else
|
184
|
+
[]
|
192
185
|
end
|
186
|
+
rescue NameError
|
187
|
+
[]
|
188
|
+
end
|
193
189
|
|
194
|
-
|
195
|
-
|
196
|
-
|
190
|
+
hook = lambda do |hook_cls|
|
191
|
+
lambda do |method_id|
|
192
|
+
method = begin
|
193
|
+
hook_cls.instance_method(method_id)
|
194
|
+
rescue NameError
|
195
|
+
HookLog.load_error [ hook_cls, method_id ].join('[#.]'), "Method #{hook_cls} #{method_id} is not accessible: #{$!}" if HookLog.enabled?
|
196
|
+
next
|
197
|
+
end
|
197
198
|
|
198
|
-
|
199
|
-
|
200
|
-
|
199
|
+
package = config.lookup_package(hook_cls, method)
|
200
|
+
# doing this check first returned early in 98.7% of cases in sample_app_6th_ed
|
201
|
+
next unless package
|
201
202
|
|
202
|
-
|
203
|
+
# Don't try and trace the AppMap methods or there will be
|
204
|
+
# a stack overflow in the defined hook method.
|
205
|
+
next if %w[Marshal AppMap ActiveSupport].member?((hook_cls&.name || '').split('::')[0])
|
203
206
|
|
204
|
-
|
207
|
+
next if method_id == :call
|
205
208
|
|
206
|
-
|
209
|
+
next if self.class.already_hooked?(method)
|
207
210
|
|
208
|
-
|
209
|
-
# Skip methods that have no instruction sequence, as they are either have no body or they are or native.
|
210
|
-
# TODO: Figure out how to tell the difference?
|
211
|
-
next unless disasm
|
211
|
+
HookLog.log "Examining #{hook_cls} #{method.name}" if HookLog.enabled?
|
212
212
|
|
213
|
-
|
213
|
+
disasm = RubyVM::InstructionSequence.disasm(method)
|
214
|
+
# Skip methods that have no instruction sequence, as they are either have no body or they are or native.
|
215
|
+
# TODO: Figure out how to tell the difference?
|
216
|
+
next unless disasm
|
217
|
+
|
218
|
+
package.handler_class.new(package, hook_cls, method).activate
|
219
|
+
end
|
214
220
|
end
|
215
|
-
end
|
216
221
|
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
222
|
+
start = Time.now
|
223
|
+
instance_methods.each(&hook.(cls))
|
224
|
+
begin
|
225
|
+
# NoMethodError: private method `singleton_class' called for Rack::MiniProfiler:Class
|
226
|
+
class_methods.each(&hook.(cls.singleton_class)) if cls.respond_to?(:singleton_class)
|
227
|
+
rescue NameError
|
228
|
+
# NameError:
|
229
|
+
# uninitialized constant Faraday::Connection
|
230
|
+
warn "NameError in #{__FILE__}: #{$!.message}"
|
231
|
+
end
|
232
|
+
elapsed = Time.now - start
|
233
|
+
if location.index(Bundler.bundle_path.to_s) == 0
|
234
|
+
package_tokens = location[Bundler.bundle_path.to_s.length + 1..-1].split('/')
|
235
|
+
@module_load_times[package_tokens[1]] += elapsed
|
236
|
+
else
|
237
|
+
file_path = location[Dir.pwd.length + 1..-1]
|
238
|
+
if file_path
|
239
|
+
location = file_path.split('/', 3)[0..1].join('/')
|
240
|
+
@module_load_times[location] += elapsed
|
241
|
+
end
|
242
|
+
end
|
231
243
|
end
|
232
244
|
end
|
233
245
|
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
module AppMap
|
2
|
+
class HookLog
|
3
|
+
LOG = (ENV['APPMAP_DEBUG'] == 'true' || ENV['DEBUG'] == 'true')
|
4
|
+
LOG_HOOK = (ENV['DEBUG_HOOK'] == 'true' || ENV['APPMAP_LOG_HOOK'] == 'true')
|
5
|
+
LOG_HOOK_FILE = (ENV['APPMAP_LOG_HOOK_FILE'] || 'appmap_hook.log')
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@file_handle = self.class.send :open_log_file
|
9
|
+
@elapsed = Hash.new { |h, k| h[k] = [] }
|
10
|
+
|
11
|
+
at_exit do
|
12
|
+
@file_handle.puts 'Elapsed time:'
|
13
|
+
@elapsed.keys.each do |k|
|
14
|
+
@file_handle.puts "#{k}:\t#{@elapsed[k].sum}"
|
15
|
+
end
|
16
|
+
@file_handle.flush
|
17
|
+
@file_handle.close
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def start_time(timer)
|
22
|
+
@elapsed[timer] << [Util.gettime]
|
23
|
+
end
|
24
|
+
|
25
|
+
def end_time(timer)
|
26
|
+
unless @elapsed[timer].last.is_a?(Array)
|
27
|
+
warn "AppMap: Unbalanced timing data in hook log"
|
28
|
+
@elapsed[timer].pop
|
29
|
+
return
|
30
|
+
end
|
31
|
+
|
32
|
+
@elapsed[timer][-1] = Util.gettime - @elapsed[timer].last[0]
|
33
|
+
end
|
34
|
+
|
35
|
+
class << self
|
36
|
+
def enabled?
|
37
|
+
LOG || LOG_HOOK
|
38
|
+
end
|
39
|
+
|
40
|
+
def builtin(class_name, &block)
|
41
|
+
return yield unless enabled?
|
42
|
+
|
43
|
+
begin
|
44
|
+
log "eager\tbegin\tInitiating eager hook for #{class_name}"
|
45
|
+
@hook_log.start_time :eager
|
46
|
+
|
47
|
+
yield
|
48
|
+
ensure
|
49
|
+
@hook_log.end_time :eager
|
50
|
+
log "eager\tend\tCompleted eager hook for #{class_name}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def on_load(location, &block)
|
55
|
+
return yield unless enabled?
|
56
|
+
|
57
|
+
begin
|
58
|
+
log "on-load\tbegin\tInitiating on-load hook for class or module defined at location #{location}"
|
59
|
+
@hook_log.start_time :on_load
|
60
|
+
|
61
|
+
yield
|
62
|
+
ensure
|
63
|
+
@hook_log.end_time :on_load
|
64
|
+
log "on-load\tend\tCompleted on-load hook for location #{location}"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def load_error(name, msg)
|
69
|
+
log "load_error\t#{name}\t#{msg}"
|
70
|
+
end
|
71
|
+
|
72
|
+
def log(msg)
|
73
|
+
unless HookLog.enabled?
|
74
|
+
warn "AppMap: HookLog is not enabled. Disregarding message #{msg}"
|
75
|
+
return
|
76
|
+
end
|
77
|
+
|
78
|
+
@hook_log ||= HookLog.new
|
79
|
+
@hook_log.log msg
|
80
|
+
end
|
81
|
+
|
82
|
+
protected def open_log_file
|
83
|
+
if LOG_HOOK_FILE == 'stderr'
|
84
|
+
$stderr
|
85
|
+
else
|
86
|
+
File.open(LOG_HOOK_FILE, 'w')
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def log(msg)
|
92
|
+
if LOG_HOOK_FILE == 'stderr'
|
93
|
+
msg = "AppMap: #{msg}"
|
94
|
+
end
|
95
|
+
msg = "#{Util.gettime}\t#{msg}"
|
96
|
+
@file_handle.puts(msg)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|