Class: AppMap::Config

Inherits:
Object
  • Object
show all
Defined in:
lib/appmap/config.rb

Defined Under Namespace

Classes: Hook, Package

Constant Summary collapse

OPENSSL_PACKAGES =
Package.build_from_path('openssl', package_name: 'openssl', labels: %w[security crypto])
HOOKED_METHODS =

Methods that should always be hooked, with their containing package and labels that should be applied to them.

{
  'ActiveSupport::SecurityUtils' => Hook.new(:secure_compare, Package.build_from_path('active_support', package_name: 'active_support', labels: %w[security crypto])),
  'ActionView::Renderer' => Hook.new(:render, Package.build_from_path('action_view', package_name: 'action_view', labels: %w[view]))
}.freeze
BUILTIN_METHODS =
{
  'OpenSSL::PKey::PKey' => Hook.new(:sign, OPENSSL_PACKAGES),
  'Digest::Instance' => Hook.new(:digest, OPENSSL_PACKAGES),
  'OpenSSL::X509::Request' => Hook.new(%i[sign verify], OPENSSL_PACKAGES),
  'OpenSSL::PKCS5' => Hook.new(%i[pbkdf2_hmac_sha1 pbkdf2_hmac], OPENSSL_PACKAGES),
  'OpenSSL::Cipher' => Hook.new(%i[encrypt decrypt final], OPENSSL_PACKAGES),
  'OpenSSL::X509::Certificate' => Hook.new(:sign, OPENSSL_PACKAGES),
  'Net::HTTP' => Hook.new(:request, Package.build_from_path('net/http', package_name: 'net/http', labels: %w[http io])),
  'Net::SMTP' => Hook.new(:send, Package.build_from_path('net/smtp', package_name: 'net/smtp', labels: %w[smtp email io])),
  'Net::POP3' => Hook.new(:mails, Package.build_from_path('net/pop3', package_name: 'net/pop', labels: %w[pop pop3 email io])),
  'Net::IMAP' => Hook.new(:send_command, Package.build_from_path('net/imap', package_name: 'net/imap', labels: %w[imap email io])),
  'Marshal' => Hook.new(%i[dump load], Package.build_from_path('marshal', labels: %w[serialization marshal])),
  'Psych' => Hook.new(%i[dump dump_stream load load_stream parse parse_stream], Package.build_from_path('yaml', package_name: 'psych', labels: %w[serialization yaml])),
  'JSON::Ext::Parser' => Hook.new(:parse, Package.build_from_path('json', package_name: 'json', labels: %w[serialization json])),
  'JSON::Ext::Generator::State' => Hook.new(:generate, Package.build_from_path('json', package_name: 'json', labels: %w[serialization json])),
}.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, packages = []) ⇒ Config

Returns a new instance of Config.



83
84
85
86
# File 'lib/appmap/config.rb', line 83

def initialize(name, packages = [])
  @name = name
  @packages = packages
end

Instance Attribute Details

#nameObject (readonly)

Returns the value of attribute name.



81
82
83
# File 'lib/appmap/config.rb', line 81

def name
  @name
end

#packagesObject (readonly)

Returns the value of attribute packages.



81
82
83
# File 'lib/appmap/config.rb', line 81

def packages
  @packages
end

Class Method Details

.load(config_data) ⇒ Object

Loads configuration from a Hash.



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/appmap/config.rb', line 96

def load(config_data)
  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.flatten
  Config.new config_data['name'], packages
end

.load_from_file(config_file_name) ⇒ Object

Loads configuration data from a file, specified by the file name.



90
91
92
93
# File 'lib/appmap/config.rb', line 90

def load_from_file(config_file_name)
  require 'yaml'
  load YAML.safe_load(::File.read(config_file_name))
end

Instance Method Details

#always_hook?(defined_class, method_name) ⇒ Boolean

Returns:

  • (Boolean)


142
143
144
# File 'lib/appmap/config.rb', line 142

def always_hook?(defined_class, method_name)
  !!find_package(defined_class, method_name)
end

#find_hook(defined_class) ⇒ Object



153
154
155
# File 'lib/appmap/config.rb', line 153

def find_hook(defined_class)
  HOOKED_METHODS[defined_class] || BUILTIN_METHODS[defined_class]
end

#find_package(defined_class, method_name) ⇒ Object



146
147
148
149
150
151
# File 'lib/appmap/config.rb', line 146

def find_package(defined_class, method_name)
  hook = find_hook(defined_class)
  return nil unless hook

  Array(hook.method_names).include?(method_name) ? hook.package : nil
end

#included_by_location?(method) ⇒ Boolean

Returns:

  • (Boolean)


138
139
140
# File 'lib/appmap/config.rb', line 138

def included_by_location?(method)
  !!package_for_method(method)
end

#package_for_method(method) ⇒ Object



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/appmap/config.rb', line 122

def package_for_method(method)
  defined_class, _, method_name = ::AppMap::Hook.qualify_method_name(method)
  package = find_package(defined_class, method_name)
  return package if package

  location = method.source_location
  location_file, = location
  return unless location_file

  location_file = location_file[Dir.pwd.length + 1..-1] if location_file.index(Dir.pwd) == 0
  packages.find do |pkg|
    (location_file.index(pkg.path) == 0) &&
      !pkg.exclude.find { |p| location_file.index(p) }
  end
end

#to_hObject



115
116
117
118
119
120
# File 'lib/appmap/config.rb', line 115

def to_h
  {
    name: name,
    packages: packages.map(&:to_h)
  }
end