Class: Contrast::Agent::Middleware

Inherits:
Object
  • Object
show all
Includes:
Components::Interface
Defined in:
lib/contrast/agent/middleware.rb

Overview

This class allows the Agent to plug into the Rack middleware stack. When the application is first started, we initialize ourselves as a rack middleware inside of #initialize. Afterwards, we process each http request and response as it goes through the middleware stack inside of #call.

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Components::Interface

included

Constructor Details

#initialize(app, _legacy_param = nil) ⇒ Middleware

Allows the Agent to function as a middleware. We perform all our one-time whole-app routines in here since we’re only going to be initialized a single time. Our initialization order is:

  • capture the application

  • setup the Agent

  • startup the Agent

Parameters:

  • app (Rack::Application)

    the application to be instrumented

  • _legacy_param (nil) (defaults to: nil)

    was a flag we no longer need, but Sinatra may call it



37
38
39
40
41
42
43
44
45
46
47
# File 'lib/contrast/agent/middleware.rb', line 37

def initialize app, _legacy_param = nil
  @app = app  # THIS MUST BE FIRST AND ALWAYS SET!
  setup_agent # THIS MUST BE SECOND AND ALWAYS CALLED!
  unless AGENT.enabled?
    logger.error(
        'The Agent was unable to initialize before the application middleware was initialized. Disabling permanently.')
    AGENT.disable! # ensure the agent is disabled (probably redundant)
    return
  end
  agent_startup_routine
end

Instance Attribute Details

#appObject (readonly)

Returns the value of attribute app.



27
28
29
# File 'lib/contrast/agent/middleware.rb', line 27

def app
  @app
end

Instance Method Details

#agent_startup_routineObject

Startup the Agent as part of the initialization process:

  • start the service sending thread, responsible for sending and processing messages

  • start the heartbeat thread, which triggers service startup

  • start instrumenting libraries and do a ‘catchup’ patch for everything we didn’t see get loaded

  • enable TracePoint, which handles all class loads and required instrumentation going forward



57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/contrast/agent/middleware.rb', line 57

def agent_startup_routine
  logger.debug_with_time('middleware: starting service') do
    Contrast::Agent.thread_watcher.ensure_running?
  end

  logger.debug_with_time('middleware: instrument shared libraries and patch') do
    Contrast::Agent::Patching::Policy::Patcher.patch
  end

  AGENT.enable_tracepoint
  Contrast::Agent::AtExitHook.exit_hook
end

#call(env) ⇒ Array, Rack::Response

This is where we’re hooked into the middleware stack. If the agent is enabled, we’re ready to do some processing on a per request basis. If not, we just pass the request along to the next middleware in the stack.

Parameters:

  • env (Hash)

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

Returns:

  • (Array, Rack::Response)

    the Response of this and subsequent Middlewares to be passed back to the user up the Rack framework.



78
79
80
81
82
83
84
85
86
87
# File 'lib/contrast/agent/middleware.rb', line 78

def call env
  Contrast::Utils::HeapDumpUtil.run

  if AGENT.enabled?
    Contrast::Agent::StaticAnalysis.catchup
    call_with_agent(env)
  else
    app.call(env)
  end
end