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[[] dig values fetch], %w[http.session.read]), method_hook('ActionDispatch::Request::Session', i[destroy[]= clear update delete merge], %w[http.session.write]), method_hook('ActionDispatch::Cookies::CookieJar', i[[]= clear update delete recycle], %w[http.session.read]), method_hook('ActionDispatch::Cookies::CookieJar', i[[]= clear update delete recycle], %w[http.session.write]), 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[load load_stream parse parse_stream], Package.build_from_path('yaml', package_name: 'psych', labels: %w[format.yaml.parse])), TargetMethods.new(i[dump dump_stream], Package.build_from_path('yaml', package_name: 'psych', labels: %w[format.yaml.generate])), ], 'JSON::Ext::Parser' => TargetMethods.new(:parse, Package.build_from_path('json', package_name: 'json', labels: %w[format.json.parse])), 'JSON::Ext::Generator::State' => TargetMethods.new(:generate, Package.build_from_path('json', package_name: 'json', labels: %w[format.json.generate])), }.freeze
Instance Attribute Summary collapse
-
#appmap_dir ⇒ Object
readonly
Returns the value of attribute appmap_dir.
-
#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.
-
#swagger_config ⇒ Object
readonly
Returns the value of attribute swagger_config.
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: [], swagger_config: Swagger::Configuration.new, 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: [], swagger_config: Swagger::Configuration.new, exclude: [], functions: []) ⇒ Config
Returns a new instance of Config.
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 |
# File 'lib/appmap/config.rb', line 232 def initialize(name, packages: [], swagger_config: Swagger::Configuration.new, exclude: [], functions: []) @name = name @appmap_dir = AppMap::DEFAULT_APPMAP_DIR @packages = packages @swagger_config = swagger_config @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
#appmap_dir ⇒ Object (readonly)
Returns the value of attribute appmap_dir.
230 231 232 |
# File 'lib/appmap/config.rb', line 230 def appmap_dir @appmap_dir end |
#builtin_hooks ⇒ Object (readonly)
Returns the value of attribute builtin_hooks.
230 231 232 |
# File 'lib/appmap/config.rb', line 230 def builtin_hooks @builtin_hooks end |
#exclude ⇒ Object (readonly)
Returns the value of attribute exclude.
230 231 232 |
# File 'lib/appmap/config.rb', line 230 def exclude @exclude end |
#hooked_methods ⇒ Object (readonly)
Returns the value of attribute hooked_methods.
230 231 232 |
# File 'lib/appmap/config.rb', line 230 def hooked_methods @hooked_methods end |
#name ⇒ Object (readonly)
Returns the value of attribute name.
230 231 232 |
# File 'lib/appmap/config.rb', line 230 def name @name end |
#packages ⇒ Object (readonly)
Returns the value of attribute packages.
230 231 232 |
# File 'lib/appmap/config.rb', line 230 def packages @packages end |
#swagger_config ⇒ Object (readonly)
Returns the value of attribute swagger_config.
230 231 232 |
# File 'lib/appmap/config.rb', line 230 def swagger_config @swagger_config end |
Class Method Details
.load(config_data) ⇒ Object
Loads configuration from a Hash.
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 |
# File 'lib/appmap/config.rb', line 315 def load(config_data) name = config_data['name'] || Service::Guesser.guess_name config_params = { exclude: config_data['exclude'] }.compact if config_data['functions'] config_params[:functions] = config_data['functions'].map do |function_data| package = function_data['package'] cls = function_data['class'] functions = function_data['function'] || function_data['functions'] raise %q(AppMap config 'function' element should specify 'package', 'class' and 'function' or 'functions') 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 end config_params[:packages] = \ if config_data['packages'] config_data['packages'].map do |package| gem = package['gem'] path = package['path'] raise %q(AppMap config 'package' element 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 else Array(Service::Guesser.guess_paths).map do |path| Package.build_from_path(path) end end if config_data['swagger'] swagger_config = Swagger::Configuration.load(config_data['swagger']) config_params[:swagger_config] = swagger_config end Config.new name, config_params end |
.load_from_file(config_file_name) ⇒ Object
Loads configuration data from a file, specified by the file name.
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 |
# File 'lib/appmap/config.rb', line 265 def load_from_file(config_file_name) logo = lambda do Util.color(" ___ __ ___\n / _ | ___ ___ / |/ /__ ____\n / __ |/ _ \\\\/ _ \\\\/ /|_/ / _ `/ _ \\\\\n /_/ |_/ .__/ .__/_/ /_/\\\\_,_/ .__/\n /_/ /_/ /_/\n LOGO\n end\n\n config_present = true if File.exists?(config_file_name)\n\n config_data = if config_present\n YAML.safe_load(::File.read(config_file_name))\n else\n warn logo.()\n warn ''\n warn Util.color(%Q|NOTICE: The AppMap config file \#{config_file_name} was not found!|, :magenta, bold: true)\n warn ''\n warn Util.color(<<~MISSING_FILE_MSG, :magenta)\n AppMap uses this file to customize its behavior. For example, you can use\n the 'packages' setting to indicate which local file paths and dependency\n gems you want to include in the AppMap. Since you haven't provided specific\n settings, the appmap gem will try and guess some reasonable defaults.\n To suppress this message, create the file:\n \n \#{Pathname.new(config_file_name).expand_path}\n \n Here are the default settings that will be used in the meantime. You can\n copy and paste this example to start your appmap.yml.\n MISSING_FILE_MSG\n {}\n end\n load(config_data).tap do |config|\n config_yaml = {\n 'name' => config.name,\n 'packages' => config.packages.select{|p| p.path}.map do |pkg|\n { 'path' => pkg.path }\n end,\n 'exclude' => []\n }.compact\n unless config_present\n warn Util.color(YAML.dump(config_yaml), :magenta)\n warn logo.()\n end\n end\nend\n", :magenta) |
.method_hook(cls, method_names, labels) ⇒ Object
147 148 149 |
# File 'lib/appmap/config.rb', line 147 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
137 138 139 140 141 142 143 144 145 |
# File 'lib/appmap/config.rb', line 137 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
416 417 418 |
# File 'lib/appmap/config.rb', line 416 def lookup_package(cls, method) LookupPackage.new(self, cls, method).package end |
#never_hook?(cls, method) ⇒ Boolean
420 421 422 423 |
# File 'lib/appmap/config.rb', line 420 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.
376 377 378 379 |
# File 'lib/appmap/config.rb', line 376 def path_enabled?(path) path = AppMap::Util.normalize_path(path) @hook_paths.find { |hook_path| path.index(hook_path) == 0 } end |
#to_h ⇒ Object
366 367 368 369 370 371 372 373 |
# File 'lib/appmap/config.rb', line 366 def to_h { name: name, packages: packages.map(&:to_h), functions: @functions.map(&:to_h), exclude: exclude }.compact end |