class OpticsAgent::Agent

Attributes

logger[RW]
report_traces[R]
schema[R]

Public Class Methods

new() click to toggle source
# File lib/optics-agent/agent.rb, line 24
def initialize
  @stats_reporting_thread = nil
  @query_queue = []
  @semaphone = Mutex.new

  # set defaults
  @configuration = Configuration.new
end

Public Instance Methods

add_query(*args) click to toggle source
# File lib/optics-agent/agent.rb, line 166
def add_query(*args)
  @semaphone.synchronize {
    debug { "adding query to queue, queue length was #{@query_queue.length}" }
    @query_queue << args
  }
end
clear_query_queue() click to toggle source
# File lib/optics-agent/agent.rb, line 173
def clear_query_queue
  @semaphone.synchronize {
    debug { "clearing query queue, queue length was #{@query_queue.length}" }
    queue = @query_queue
    @query_queue = []
    queue
  }
end
configure(&block) click to toggle source
# File lib/optics-agent/agent.rb, line 33
def configure(&block)
  @configuration.instance_eval(&block)

  if @configuration.schema && @schema != @configuration.schema
    instrument_schema(@configuration.schema)
  end
end
debug(message = nil) { || ... } click to toggle source

Should we be using built in debug levels rather than our own “debug” flag?

# File lib/optics-agent/agent.rb, line 220
def debug(message = nil)
  if @configuration.debug
    message = yield unless message
    self.class.logger.info "optics-agent: DEBUG: #{message} <#{Process.pid} | #{Thread.current.object_id}>"
  end
end
disabled?() click to toggle source
# File lib/optics-agent/agent.rb, line 41
def disabled?
  @configuration.disable_reporting || !@configuration.api_key || !@schema
end
ensure_reporting!() click to toggle source

@deprecated Use ensure_reporting_stats! instead

# File lib/optics-agent/agent.rb, line 95
def ensure_reporting!
  ensure_reporting_stats!
end
ensure_reporting_stats!() click to toggle source

We call this method on every request to ensure that the reporting thread is active in the correct process for pre-forking webservers like unicorn

# File lib/optics-agent/agent.rb, line 81
    def ensure_reporting_stats!
      unless @schema
        warn """No schema instrumented.
Use the `schema` configuration setting, or call `agent.instrument_schema`
"""
        return
      end

      unless reporting_stats? || disabled?
        schedule_report
      end
    end
graphql_middleware() click to toggle source
# File lib/optics-agent/agent.rb, line 189
def graphql_middleware
  warn "You no longer need to pass the optics agent middleware, it now attaches itself"
end
instrument_schema(schema) click to toggle source
# File lib/optics-agent/agent.rb, line 49
    def instrument_schema(schema)
      unless @configuration.api_key
        warn """No api_key set.
Either configure it or use the OPTICS_API_KEY environment variable.
"""
        return
      end

      if @schema
        warn """Agent has already instrumented a schema.
Perhaps you are calling both `agent.configure { schema YourSchema }` and
`agent.instrument_schema YourSchema`?
"""
        return
      end

      @schema = schema
      @schema._attach_optics_agent(self)

      unless disabled?
        debug "spawning schema thread"
        Thread.new do
          debug "schema thread spawned"
          sleep @configuration.schema_report_delay_ms / 1000.0
          debug "running schema job"
          SchemaJob.new.perform(self)
        end
      end
    end
log(message = nil) { || ... } click to toggle source
# File lib/optics-agent/agent.rb, line 210
def log(message = nil)
  message = yield unless message
  self.class.logger.info "optics-agent: #{message}"
end
rack_middleware() click to toggle source
# File lib/optics-agent/agent.rb, line 182
def rack_middleware
  # We need to pass ourselves to the class we return here because
  # rack will instanciate it. (See comment at the top of RackMiddleware)
  OpticsAgent::RackMiddleware.agent = self
  OpticsAgent::RackMiddleware
end
report_traces?() click to toggle source
# File lib/optics-agent/agent.rb, line 45
def report_traces?
  @configuration.report_traces
end
reporting_connection() click to toggle source
# File lib/optics-agent/agent.rb, line 99
def reporting_connection
  @reporting_connection ||=
    Faraday.new(:url => @configuration.endpoint_url) do |conn|
      conn.request :retry,
                   :max => 5,
                   :interval => 0.1,
                   :max_interval => 10,
                   :backoff_factor => 2,
                   :exceptions => [Exception],
                   :retry_if => ->(env, exc) { true }
      conn.use OpticsAgent::Reporting::DetectServerSideError

      # XXX: allow setting adaptor in config
      conn.adapter :net_http_persistent
    end
end
reporting_stats?() click to toggle source
# File lib/optics-agent/agent.rb, line 116
def reporting_stats?
  @stats_reporting_thread != nil && !!@stats_reporting_thread.status
end
schedule_report() click to toggle source
# File lib/optics-agent/agent.rb, line 120
def schedule_report
  @semaphone.synchronize do
    return if reporting_stats?

    debug "spawning reporting thread"

    thread = Thread.new do
      begin
        debug "reporting thread spawned"

        report_interval = @configuration.report_interval_ms / 1000.0
        last_started = Time.now

        while true
          next_send = last_started + report_interval
          sleep_time = next_send - Time.now

          if sleep_time < 0
            warn 'Report took more than one interval! Some requests might appear at the wrong time.'
          else
            sleep sleep_time
          end

          debug "running reporting job"
          last_started = Time.now
          ReportJob.new.perform(self)
          debug "finished running reporting job"
        end
      rescue Exception => e
        warn "Stats report thread dying: #{e}"
      end
    end

    at_exit do
      if thread.status
        debug 'sending last stats report before exiting'
        thread.exit
        ReportJob.new.perform(self)
        debug 'last stats report sent'
      end
    end

    @stats_reporting_thread = thread
  end
end
send_message(path, message) click to toggle source
# File lib/optics-agent/agent.rb, line 193
def send_message(path, message)
  response = reporting_connection.post do |request|
    request.url path
    request.headers['x-api-key'] = @configuration.api_key
    request.headers['user-agent'] = "optics-agent-rb"
    request.body = message.class.encode(message)

    if @configuration.debug || @configuration.print_reports
      log "sending message: #{message.class.encode_json(message)}"
    end
  end

  if @configuration.debug || @configuration.print_reports
    log "got response body: #{response.body}"
  end
end
warn(message = nil) click to toggle source
# File lib/optics-agent/agent.rb, line 215
def warn(message = nil)
  self.class.logger.warn "optics-agent: WARNING: #{message}"
end