Class: Contrast::Framework::Manager

Inherits:
Object
  • Object
show all
Includes:
Components::Logger::InstanceMethods, ManagerExtend
Defined in:
lib/contrast/framework/manager.rb

Overview

Allows access to framework specific information

Constant Summary collapse

SUPPORTED_FRAMEWORKS =

Order here does matter as the first framework listed will be the first one we pull information from Rack will be a special case that may involve updating some logic to handle only applying Rack if Rails/Sinatra do not exist

[
  Contrast::Framework::Rails::Support, Contrast::Framework::Sinatra::Support,
  Contrast::Framework::Grape::Support, Contrast::Framework::Rack::Support
].cs__freeze

Instance Method Summary collapse

Methods included from Components::Logger::InstanceMethods

#cef_logger, #logger

Constructor Details

#initializeManager

Returns a new instance of Manager.



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/contrast/framework/manager.rb', line 31

def initialize
  @_frameworks = []
  return if Contrast::AGENT.disabled? || Contrast::Utils::JobServersRunning.job_servers_running?

  @_frameworks = SUPPORTED_FRAMEWORKS.map do |framework_klass|
    next unless enable_framework_support?(framework_klass.detection_class)

    logger.info('Framework detected. Enabling support.', framework: framework_klass.detection_class)
    framework_klass
  end

  # Delete Rack if we have more than one framework detected
  @_frameworks.delete(Contrast::Framework::Rack::Support) if @_frameworks.length > 1
  @_frameworks.compact!
end

Instance Method Details

#app_nameObject



77
78
79
# File 'lib/contrast/framework/manager.rb', line 77

def app_name
  first_framework_result(:application_name, 'root')
end

#app_rootObject



82
83
84
85
86
# File 'lib/contrast/framework/manager.rb', line 82

def app_root
  found = first_framework_result(:application_root, nil)
  found ||= ::Rack::Directory.new('').root
  found.to_s
end

#before_load_patches!Object

Patches that have to be applied as early as possible to catch calls that happen prior to the first Request, typically those around configuration.



49
50
51
52
53
54
# File 'lib/contrast/framework/manager.rb', line 49

def before_load_patches!
  @_before_load_patches ||= begin
    SUPPORTED_FRAMEWORKS.each(&:before_load_patches!)
    true
  end
end

#find_after_load_patchesSet<Contrast::Agent::Patching::Policy::AfterLoadPatch>

Return all the After Load Patches for all the Frameworks we know, even if that Framework hasn’t been detected.

Returns:



59
60
61
62
63
64
65
66
# File 'lib/contrast/framework/manager.rb', line 59

def find_after_load_patches
  patches = Set.new
  SUPPORTED_FRAMEWORKS.each do |framework|
    framework_patches = framework.after_load_patches
    patches.merge(framework_patches) if framework_patches && !framework_patches.empty?
  end
  patches
end

#find_route_discovery_dataArray<Contrast::Agent::Reporting::DiscoveredRoute>



69
70
71
# File 'lib/contrast/framework/manager.rb', line 69

def find_route_discovery_data
  routes_for_all_frameworks
end

#get_route_information(request) ⇒ Contrast::Agent::Reporting::RouteCoverage

Iterate through current frameworks and return the current request’s route. This will be the first non-nil result.

Parameters:

Returns:



131
132
133
134
# File 'lib/contrast/framework/manager.rb', line 131

def get_route_information request
  @_frameworks&.lazy&.map { |framework_support| framework_support.current_route_coverage(request) }&.
      reject(&:nil?)&.first
end

#register_late_framework(mod) ⇒ Object

Sometimes the framework we want to instrument is loaded after our agent code. To catch that case, we’ll detect if the loaded_module is the marker class for any of our supported frameworks. If it is, and we don’t already have support enabled, we’ll enable it now. We’ll also need to catch up on any other startup actions that we’ve missed. Most likely, this is only necessary for those applications which have applications mounted on them.

TODO: RUBY-1356

Parameters:

  • mod (Module)

    the module or class that was just loaded



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/contrast/framework/manager.rb', line 144

def register_late_framework mod
  return unless mod

  module_name = mod.cs__name
  # Otherwise, check if the provided module_name requires us to register a new support
  SUPPORTED_FRAMEWORKS.each do |framework|
    next if @_frameworks.include?(framework)
    next unless module_name == framework.detection_class

    @_frameworks << framework
    report = Contrast::Agent::Reporting::ApplicationUpdate.new
    # This convert here is left as it'll be easier to be replaced when the Library is being changed
    report.libraries = Contrast::Agent::Inventory::DependencyAnalysis.instance.library_pb_list
    [report, Contrast::Agent::Reporting::ApplicationInventory.new].each do |e|
      Contrast::Agent.reporter.send_event(e)
    end

    logger.info('Framework detected after initialization. Enabling support.',
                framework: framework.detection_class,
                frameworks: @_frameworks)
    break
  end
rescue StandardError => e
  logger.warn('Unable to register a late framework', e, module: mod.cs__name)
end

#retrieve_request(env) ⇒ ::Rack::Request

Build a request from the provided env, based on the framework(s) we’re currently supporting.

Parameters:

  • env (Hash)

    the various variables stored by this and other Middlewares to know the state and values of this particular Request

Returns:

  • (::Rack::Request)

    either a rack request or subclass thereof.



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/contrast/framework/manager.rb', line 93

def retrieve_request env
  return Contrast::Framework::Rack::Support.retrieve_request(env) if @_frameworks.empty?

  framework = @_frameworks[0]

  case framework.cs__name
  when 'Contrast::Framework::Rails::Support'
    Contrast::Framework::Rails::Support.retrieve_request(env)
  when 'Contrast::Framework::Grape::Support'
    Contrast::Framework::Grape::Support.retrieve_request(env)
  when 'Contrast::Framework::Sinatra::Support'
    Contrast::Framework::Sinatra::Support.retrieve_request(env)
  else
    Contrast::Framework::Rack::Support.retrieve_request(env)
  end
rescue StandardError => e
  logger.warn('Unable to retrieve_request', e)
end

#server_typeObject



73
74
75
# File 'lib/contrast/framework/manager.rb', line 73

def server_type
  first_framework_result(:server_type, 'rack')
end

#streaming?(env) ⇒ Boolean

Returns true if at least one framework is streaming the response; false if none are streaming.

Parameters:

  • env (Hash)

    the various variables stored by this and other Middlewares to know the state and values of this particular Request

Returns:

  • (Boolean)

    true if at least one framework is streaming the response; false if none are streaming



115
116
117
118
119
120
121
122
123
124
# File 'lib/contrast/framework/manager.rb', line 115

def streaming? env
  result = false
  return result if @_frameworks.empty?

  @_frameworks.each do |framework|
    result = framework.streaming?(env)
    break if result
  end
  result
end