class ElasticAPM::CentralConfig

@api private

Constants

DEFAULT_MAX_AGE

Attributes

config[R]
promise[R]
scheduled_task[R]

Public Class Methods

new(config) click to toggle source
# File lib/elastic_apm/central_config.rb, line 42
def initialize(config)
  @config = config
  @modified_options = {}
  @http = Transport::Connection::Http.new(config)
  @etag = 1
end

Public Instance Methods

assign(update) click to toggle source
# File lib/elastic_apm/central_config.rb, line 91
def assign(update)
  # For each updated option, store the original value,
  # unless already stored
  update.each_key do |key|
    @modified_options[key] ||= config.get(key.to_sym)&.value
  end

  # If the new update doesn't set a previously modified option,
  # revert it to the original
  @modified_options.each_key do |key|
    next if update.key?(key)
    update[key] = @modified_options.delete(key)
  end

  @config.replace_options(update)
end
fetch_and_apply_config() click to toggle source
# File lib/elastic_apm/central_config.rb, line 66
def fetch_and_apply_config
  @promise =
    Concurrent::Promise
    .execute { fetch_config }
    .on_success { |resp| handle_success(resp) }
    .rescue { |err| handle_error(err) }
end
fetch_config() click to toggle source
# File lib/elastic_apm/central_config.rb, line 74
def fetch_config
  resp = perform_request

  # rubocop:disable Lint/DuplicateBranch
  case resp.status
  when 200..299
    resp
  when 300..399
    resp
  when 400..499
    raise ClientError, resp
  when 500..599
    raise ServerError, resp
  end
  # rubocop:enable Lint/DuplicateBranch
end
handle_forking!() click to toggle source
# File lib/elastic_apm/central_config.rb, line 108
def handle_forking!
  stop
  start
end
start() click to toggle source
# File lib/elastic_apm/central_config.rb, line 52
def start
  return unless config.central_config?

  debug 'Starting CentralConfig'

  fetch_and_apply_config
end
stop() click to toggle source
# File lib/elastic_apm/central_config.rb, line 60
def stop
  debug 'Stopping CentralConfig'

  @scheduled_task&.cancel
end

Private Instance Methods

handle_error(error) click to toggle source

rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity

# File lib/elastic_apm/central_config.rb, line 145
def handle_error(error)
  # For tests, WebMock failures don't have real responses
  response = error.response if error.respond_to?(:response)

  debug(
    'Failed fetching config: %s, trying again in %d seconds',
    response&.body, DEFAULT_MAX_AGE
  )

  assign({})

  schedule_next_fetch(response)
end
handle_success(resp) click to toggle source

rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity

# File lib/elastic_apm/central_config.rb, line 116
def handle_success(resp)
  if (etag = resp.headers['Etag'])
    @etag = etag
  end

  if resp.status == 304
    debug 'Received 304 Not Modified'
  else
    if resp.body && !resp.body.empty?
      update = JSON.parse(resp.body.to_s)
      assign(update)
    end

    if update&.any?
      info 'Updated config from Kibana'
      debug 'Modified: %s', update.inspect
      debug 'Modified original options: %s', @modified_options.inspect
    end
  end

  schedule_next_fetch(resp)

  true
rescue Exception => e
  error 'Failed to apply remote config, %s', e.inspect
  debug { e.backtrace.join('\n') }
end
headers() click to toggle source
# File lib/elastic_apm/central_config.rb, line 171
def headers
  { 'If-None-Match': @etag }
end
perform_request() click to toggle source
# File lib/elastic_apm/central_config.rb, line 159
def perform_request
  @http.get(server_url, headers: headers)
end
schedule_next_fetch(resp = nil) click to toggle source
# File lib/elastic_apm/central_config.rb, line 175
def schedule_next_fetch(resp = nil)
  headers = resp&.headers
  seconds =
    if headers && headers['Cache-Control']
      CacheControl.new(headers['Cache-Control']).max_age
    else
      DEFAULT_MAX_AGE
    end

  @scheduled_task =
    Concurrent::ScheduledTask
    .execute(seconds) { fetch_and_apply_config }
end
server_url() click to toggle source
# File lib/elastic_apm/central_config.rb, line 163
def server_url
  @server_url ||=
    config.server_url +
    '/config/v1/agents' \
    "?service.name=#{CGI.escape(config.service_name)}" \
    "&service.environment=#{CGI.escape(config.environment || '')}"
end