Class: AppMap::Config
- Inherits:
-
Object
- Object
- AppMap::Config
- Defined in:
- lib/appmap/config.rb
Defined Under Namespace
Classes: LookupPackage, Package
Constant Summary collapse
- METHOD_HOOKS =
Hook well-known functions. When a function configured here is available in the bundle, it will be hooked with the predefined labels specified here. If any of these hooks are not desired, they can be disabled in the
excludesection of appmap.yml. package_hooks('actionview', [ method_hook('ActionView::Renderer', :render, %w[mvc.view]), method_hook('ActionView::TemplateRenderer', :render, %w[mvc.view]), method_hook('ActionView::PartialRenderer', :render, %w[mvc.view]) ], handler_class: AppMap::Handler::Rails::Template::RenderHandler, package_name: 'action_view' ), package_hooks('actionview', [ method_hook('ActionView::Resolver', i[find_all find_all_anywhere], %w[mvc.template.resolver]) ], handler_class: AppMap::Handler::Rails::Template::ResolverHandler, package_name: 'action_view' ), package_hooks('actionpack', [ method_hook('ActionDispatch::Request::Session', i[destroy [] dig values []= clear update delete fetch merge], %w[http.session]), method_hook('ActionDispatch::Cookies::CookieJar', i[[]= clear update delete recycle], %w[http.session]), method_hook('ActionDispatch::Cookies::EncryptedCookieJar', i[[]= clear update delete recycle], %w[http.cookie crypto.encrypt]) ], package_name: 'action_dispatch' ), package_hooks('cancancan', [ method_hook('CanCan::ControllerAdditions', i[ can? cannot?], %w[security.authorization]), method_hook('CanCan::Ability', i[], %w[security.authorization]) ] ), package_hooks('actionpack', [ method_hook('ActionController::Instrumentation', i[process_action send_file send_data redirect_to], %w[mvc.controller]) ], package_name: 'action_controller' ) ].flatten.freeze
- OPENSSL_PACKAGES =
->(labels) { Package.build_from_path('openssl', package_name: 'openssl', labels: labels) }
- BUILTIN_HOOKS =
Hook functions which are builtin to Ruby. Because they are builtins, they may be loaded before appmap. Therefore, we can’t rely on TracePoint to report the loading of this code.
{ 'OpenSSL::PKey::PKey' => TargetMethods.new(:sign, OPENSSL_PACKAGES.(%w[crypto.pkey])), 'OpenSSL::X509::Request' => TargetMethods.new(i[sign verify], OPENSSL_PACKAGES.(%w[crypto.x509])), 'OpenSSL::PKCS5' => TargetMethods.new(i[pbkdf2_hmac_sha1 pbkdf2_hmac], OPENSSL_PACKAGES.(%w[crypto.pkcs5])), 'OpenSSL::Cipher' => [ TargetMethods.new(i[encrypt], OPENSSL_PACKAGES.(%w[crypto.encrypt])), TargetMethods.new(i[decrypt], OPENSSL_PACKAGES.(%w[crypto.decrypt])) ], 'ActiveSupport::Callbacks::CallbackSequence' => [ TargetMethods.new(:invoke_before, Package.build_from_gem('activesupport', force: true, package_name: 'active_support', labels: %w[mvc.before_action])), TargetMethods.new(:invoke_after, Package.build_from_gem('activesupport', force: true, package_name: 'active_support', labels: %w[mvc.after_action])), ], 'ActiveSupport::SecurityUtils' => TargetMethods.new(:secure_compare, Package.build_from_gem('activesupport', force: true, package_name: 'active_support/security_utils', labels: %w[crypto.secure_compare])), 'OpenSSL::X509::Certificate' => TargetMethods.new(:sign, OPENSSL_PACKAGES.(%w[crypto.x509])), 'Net::HTTP' => TargetMethods.new(:request, Package.build_from_path('net/http', package_name: 'net/http', labels: %w[protocol.http]).tap do |package| package.handler_class = AppMap::Handler::NetHTTP end), 'Net::SMTP' => TargetMethods.new(:send, Package.build_from_path('net/smtp', package_name: 'net/smtp', labels: %w[protocol.email.smtp])), 'Net::POP3' => TargetMethods.new(:mails, Package.build_from_path('net/pop3', package_name: 'net/pop', labels: %w[protocol.email.pop])), # This is happening: Method send_command not found on Net::IMAP # 'Net::IMAP' => TargetMethods.new(:send_command, Package.build_from_path('net/imap', package_name: 'net/imap', labels: %w[protocol.email.imap])), # 'Marshal' => TargetMethods.new(%i[dump load], Package.build_from_path('marshal', labels: %w[format.marshal])), 'Psych' => TargetMethods.new(i[dump dump_stream load load_stream parse parse_stream], Package.build_from_path('yaml', package_name: 'psych', labels: %w[format.yaml])), 'JSON::Ext::Parser' => TargetMethods.new(:parse, Package.build_from_path('json', package_name: 'json', labels: %w[format.json])), 'JSON::Ext::Generator::State' => TargetMethods.new(:generate, Package.build_from_path('json', package_name: 'json', labels: %w[format.json])), }.freeze
Instance Attribute Summary collapse
-
#builtin_hooks ⇒ Object
readonly
Returns the value of attribute builtin_hooks.
-
#exclude ⇒ Object
readonly
Returns the value of attribute exclude.
-
#hooked_methods ⇒ Object
readonly
Returns the value of attribute hooked_methods.
-
#name ⇒ Object
readonly
Returns the value of attribute name.
-
#packages ⇒ Object
readonly
Returns the value of attribute packages.
Class Method Summary collapse
-
.load(config_data) ⇒ Object
Loads configuration from a Hash.
-
.load_from_file(config_file_name) ⇒ Object
Loads configuration data from a file, specified by the file name.
- .method_hook(cls, method_names, labels) ⇒ Object
- .package_hooks(gem_name, methods, handler_class: nil, package_name: nil) ⇒ Object
Instance Method Summary collapse
-
#initialize(name, packages, exclude: [], functions: []) ⇒ Config
constructor
A new instance of Config.
- #lookup_package(cls, method) ⇒ Object
- #never_hook?(cls, method) ⇒ Boolean
-
#path_enabled?(path) ⇒ Boolean
Determines if methods defined in a file path should possibly be hooked.
- #to_h ⇒ Object
Constructor Details
#initialize(name, packages, exclude: [], functions: []) ⇒ Config
Returns a new instance of Config.
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 |
# File 'lib/appmap/config.rb', line 223 def initialize(name, packages, exclude: [], functions: []) @name = name @packages = packages @hook_paths = Set.new(packages.map(&:path)) @exclude = exclude @builtin_hooks = BUILTIN_HOOKS @functions = functions @hooked_methods = METHOD_HOOKS.each_with_object(Hash.new { |h,k| h[k] = [] }) do |cls_target_methods, hooked_methods| hooked_methods[cls_target_methods.cls] << cls_target_methods.target_methods end functions.each do |func| = {} [:labels] = func.labels if func.labels @hooked_methods[func.cls] << TargetMethods.new(func.function_names, Package.build_from_path(func.package, )) end @hooked_methods.each_value do |hooks| Array(hooks).each do |hook| @hook_paths << hook.package.path end end end |
Instance Attribute Details
#builtin_hooks ⇒ Object (readonly)
Returns the value of attribute builtin_hooks.
221 222 223 |
# File 'lib/appmap/config.rb', line 221 def builtin_hooks @builtin_hooks end |
#exclude ⇒ Object (readonly)
Returns the value of attribute exclude.
221 222 223 |
# File 'lib/appmap/config.rb', line 221 def exclude @exclude end |
#hooked_methods ⇒ Object (readonly)
Returns the value of attribute hooked_methods.
221 222 223 |
# File 'lib/appmap/config.rb', line 221 def hooked_methods @hooked_methods end |
#name ⇒ Object (readonly)
Returns the value of attribute name.
221 222 223 |
# File 'lib/appmap/config.rb', line 221 def name @name end |
#packages ⇒ Object (readonly)
Returns the value of attribute packages.
221 222 223 |
# File 'lib/appmap/config.rb', line 221 def packages @packages end |
Class Method Details
.load(config_data) ⇒ Object
Loads configuration from a Hash.
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 |
# File 'lib/appmap/config.rb', line 256 def load(config_data) functions = (config_data['functions'] || []).map do |function_data| package = function_data['package'] cls = function_data['class'] functions = function_data['function'] || function_data['functions'] raise 'AppMap class configuration should specify package, class and function(s)' unless package && cls && functions functions = Array(functions).map(&:to_sym) labels = function_data['label'] || function_data['labels'] labels = Array(labels).map(&:to_s) if labels Function.new(package, cls, labels, functions) end packages = (config_data['packages'] || []).map do |package| gem = package['gem'] path = package['path'] raise 'AppMap package configuration should specify gem or path, not both' if gem && path if gem shallow = package['shallow'] # shallow is true by default for gems shallow = true if shallow.nil? Package.build_from_gem(gem, exclude: package['exclude'] || [], shallow: shallow) else Package.build_from_path(path, exclude: package['exclude'] || [], shallow: package['shallow']) end end.compact exclude = config_data['exclude'] || [] Config.new config_data['name'], packages, exclude: exclude, functions: functions end |
.load_from_file(config_file_name) ⇒ Object
Loads configuration data from a file, specified by the file name.
250 251 252 253 |
# File 'lib/appmap/config.rb', line 250 def load_from_file(config_file_name) require 'yaml' load YAML.safe_load(::File.read(config_file_name)) end |
.method_hook(cls, method_names, labels) ⇒ Object
143 144 145 |
# File 'lib/appmap/config.rb', line 143 def method_hook(cls, method_names, labels) MethodHook.new(cls, method_names, labels) end |
.package_hooks(gem_name, methods, handler_class: nil, package_name: nil) ⇒ Object
133 134 135 136 137 138 139 140 141 |
# File 'lib/appmap/config.rb', line 133 def package_hooks(gem_name, methods, handler_class: nil, package_name: nil) Array(methods).map do |method| package = Package.build_from_gem(gem_name, package_name: package_name, labels: method.labels, shallow: false, optional: true) next unless package package.handler_class = handler_class if handler_class ClassTargetMethods.new(method.cls, TargetMethods.new(Array(method.method_names), package)) end.compact end |
Instance Method Details
#lookup_package(cls, method) ⇒ Object
336 337 338 |
# File 'lib/appmap/config.rb', line 336 def lookup_package(cls, method) LookupPackage.new(self, cls, method).package end |
#never_hook?(cls, method) ⇒ Boolean
340 341 342 343 |
# File 'lib/appmap/config.rb', line 340 def never_hook?(cls, method) _, separator, = ::AppMap::Hook.qualify_method_name(method) return true if exclude.member?(cls.name) || exclude.member?([ cls.name, separator, method.name ].join) end |
#path_enabled?(path) ⇒ Boolean
Determines if methods defined in a file path should possibly be hooked.
296 297 298 299 |
# File 'lib/appmap/config.rb', line 296 def path_enabled?(path) path = AppMap::Util.normalize_path(path) @hook_paths.find { |hook_path| path.index(hook_path) == 0 } end |
#to_h ⇒ Object
286 287 288 289 290 291 292 293 |
# File 'lib/appmap/config.rb', line 286 def to_h { name: name, packages: packages.map(&:to_h), functions: @functions.map(&:to_h), exclude: exclude } end |