class ElasticAPM::Agent

@api private
rubocop:disable Metrics/ClassLength

def self.instance # rubocop:disable Style/TrivialAccessors

rubocop:disable Style/TrivialAccessors
def self.instance # rubocop:disable Style/TrivialAccessors
  @instance
end

def self.running?

def self.running?
  !!@instance
end

def self.start(config) # rubocop:disable Metrics/MethodLength

rubocop:disable Metrics/MethodLength
def self.start(config) # rubocop:disable Metrics/MethodLength
  return @instance if @instance
  config = Config.new(config) unless config.is_a?(Config)
  unless config.enabled_environments.include?(config.environment)
    puts format(
      '%sNot tracking anything in "%s" env',
      Log::PREFIX, config.environment
    )
    return
  end
  LOCK.synchronize do
    return @instance if @instance
    @instance = new(config).start
  end
end

def self.stop

def self.stop
  LOCK.synchronize do
    return unless @instance
    @instance.stop
    @instance = nil
  end
end

def add_filter(key, callback)

def add_filter(key, callback)
  @http.filters.add(key, callback)
end

def boot_worker

def boot_worker
  debug 'Booting worker'
  @worker_thread = Thread.new do
    TimedWorker.new(
      config,
      messages,
      pending_transactions,
      http
    ).run_forever
  end
end

def build_context(rack_env)

def build_context(rack_env)
  @context_builder.build(rack_env)
end

def current_transaction

def current_transaction
  instrumenter.current_transaction
end

def enqueue_error(error)

def enqueue_error(error)
  boot_worker unless worker_running?
  messages.push(TimedWorker::ErrorMsg.new(error))
end

def enqueue_transaction(transaction)

def enqueue_transaction(transaction)
  boot_worker unless worker_running?
  pending_transactions.push(transaction)
end

def initialize(config)

def initialize(config)
  @config = config
  @messages = Queue.new
  @pending_transactions = Queue.new
  @http = Http.new(config)
  @instrumenter = Instrumenter.new(config, self)
  @context_builder = ContextBuilder.new(config)
  @error_builder = ErrorBuilder.new(config)
end

def inspect

def inspect
  '<ElasticAPM::Agent>'
end

def kill_worker

def kill_worker
  messages << TimedWorker::StopMsg.new
  if @worker_thread && !@worker_thread.join(5) # 5 secs
    raise 'Failed to wait for worker, not all messages sent'
  end
  @worker_thread = nil
end

def report(exception, handled: true)

def report(exception, handled: true)
  return if config.filter_exception_types.include?(exception.class.to_s)
  error = @error_builder.build_exception(
    exception,
    handled: handled
  )
  enqueue_error error
end

def report_message(message, backtrace: nil, **attrs)

def report_message(message, backtrace: nil, **attrs)
  error = @error_builder.build_log(
    message,
    backtrace: backtrace,
    **attrs
  )
  enqueue_error error
end

def set_custom_context(*args)

def set_custom_context(*args)
  instrumenter.set_custom_context(*args)
end

def set_tag(*args)

def set_tag(*args)
  instrumenter.set_tag(*args)
end

def set_user(*args)

def set_user(*args)
  instrumenter.set_user(*args)
end

def span(*args, &block)

def span(*args, &block)
  instrumenter.span(*args, &block)
end

def start

def start
  debug '[%s] Starting agent, reporting to %s', VERSION, config.server_url
  @instrumenter.start
  config.enabled_injectors.each do |lib|
    require "elastic_apm/injectors/#{lib}"
  end
  self
end

def stop

def stop
  @instrumenter.stop
  kill_worker
  self
end

def transaction(*args, &block)

def transaction(*args, &block)
  instrumenter.transaction(*args, &block)
end

def worker_running?

def worker_running?
  @worker_thread && @worker_thread.alive?
end