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[provider.secure_compare])),
  'ActionView::Renderer' => Hook.new(:render, Package.build_from_path('action_view', package_name: 'action_view', labels: %w[mvc.view]))
}.freeze
BUILTIN_METHODS =
{
  'OpenSSL::PKey::PKey' => Hook.new(:sign, 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[protocol.http io])),
  'Net::SMTP' => Hook.new(:send, Package.build_from_path('net/smtp', package_name: 'net/smtp', labels: %w[protocol.smtp protocol.email io])),
  'Net::POP3' => Hook.new(:mails, Package.build_from_path('net/pop3', package_name: 'net/pop', labels: %w[protocol.pop protocol.email io])),
  'Net::IMAP' => Hook.new(:send_command, Package.build_from_path('net/imap', package_name: 'net/imap', labels: %w[protocol.imap protocol.email io])),
  'Marshal' => Hook.new(i[dump load], Package.build_from_path('marshal', labels: %w[format.marshal provider.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[format.yaml provider.serialization])),
  'JSON::Ext::Parser' => Hook.new(:parse, Package.build_from_path('json', package_name: 'json', labels: %w[format.json provider.serialization])),
  'JSON::Ext::Generator::State' => Hook.new(:generate, Package.build_from_path('json', package_name: 'json', labels: %w[format.json provider.serialization])),
}.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

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



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

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

Instance Attribute Details

#excludeObject (readonly)

Returns the value of attribute exclude.



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

def exclude
  @exclude
end

#nameObject (readonly)

Returns the value of attribute name.



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

def name
  @name
end

#packagesObject (readonly)

Returns the value of attribute packages.



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

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, config_data['exclude'] || []
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

always_hook? indicates a method that should always be hooked.



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

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

#find_hook(defined_class) ⇒ Object



169
170
171
# File 'lib/appmap/config.rb', line 169

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

#find_package(defined_class, method_name) ⇒ Object



162
163
164
165
166
167
# File 'lib/appmap/config.rb', line 162

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

included_by_location? indicates a method whose source location matches a method definition that has been configured for inclusion.



158
159
160
# File 'lib/appmap/config.rb', line 158

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

#never_hook?(method) ⇒ Boolean



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

def never_hook?(method)
  defined_class, separator, method_name = ::AppMap::Hook.qualify_method_name(method)
  return true if exclude.member?(defined_class) || exclude.member?([ defined_class, separator, method_name ].join)
end

#package_for_method(method) ⇒ Object

package_for_method finds the Package, if any, which configures the hook for a method.



125
126
127
# File 'lib/appmap/config.rb', line 125

def package_for_method(method)
  package_hooked_by_class(method) || package_hooked_by_source_location(method)
end

#package_hooked_by_class(method) ⇒ Object



129
130
131
132
# File 'lib/appmap/config.rb', line 129

def package_hooked_by_class(method)
  defined_class, _, method_name = ::AppMap::Hook.qualify_method_name(method)
  return find_package(defined_class, method_name)
end

#package_hooked_by_source_location(method) ⇒ Object



134
135
136
137
138
139
140
141
142
143
144
# File 'lib/appmap/config.rb', line 134

def package_hooked_by_source_location(method)
  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
121
# File 'lib/appmap/config.rb', line 115

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