class Airbrake::SyncSender

Responsible for sending data to Airbrake synchronously via PUT or POST methods. Supports proxies.

@see AsyncSender @api private @since v1.0.0

Constants

BACKLOGGABLE_STATUS_CODES

@return [Array<Integer>] response codes that are good to be backlogged @since v6.2.0

CONTENT_TYPE

@return [String] body for HTTP requests

Public Class Methods

new(method = :post) click to toggle source

@param [Symbol] method HTTP method to use to send payload

# File lib/airbrake-ruby/sync_sender.rb, line 29
def initialize(method = :post)
  @config = Airbrake::Config.instance
  @method = method
  @rate_limit_reset = Time.now
  @backlog = Backlog.new(self) if @config.backlog
end

Public Instance Methods

close() click to toggle source

Closes all the resources that this sender has allocated.

@return [void] @since v6.2.0

# File lib/airbrake-ruby/sync_sender.rb, line 68
def close
  @backlog.close
end
send(data, promise, endpoint = @config.error_endpoint) click to toggle source

Sends a POST or PUT request to the given endpoint with the data payload.

@param [#to_json] data @param [URI::HTTPS] endpoint @return [Hash{String=>String}] the parsed HTTP response

# File lib/airbrake-ruby/sync_sender.rb, line 41
def send(data, promise, endpoint = @config.error_endpoint)
  return promise if rate_limited_ip?(promise)

  req = build_request(endpoint, data)
  return promise if missing_body?(req, promise)

  begin
    response = build_https(endpoint).request(req)
  rescue StandardError => ex
    reason = "#{LOG_LABEL} HTTP error: #{ex}"
    logger.error(reason)
    return promise.reject(reason)
  end

  parsed_resp = Response.parse(response)
  handle_rate_limit(parsed_resp)
  @backlog << [data, endpoint] if add_to_backlog?(parsed_resp)

  return promise.reject(parsed_resp['error']) if parsed_resp.key?('error')

  promise.resolve(parsed_resp)
end

Private Instance Methods

add_to_backlog?(parsed_resp) click to toggle source
# File lib/airbrake-ruby/sync_sender.rb, line 113
def add_to_backlog?(parsed_resp)
  return unless @backlog
  return unless parsed_resp.key?('code')

  BACKLOGGABLE_STATUS_CODES.include?(parsed_resp['code'])
end
build_https(uri) click to toggle source
# File lib/airbrake-ruby/sync_sender.rb, line 74
def build_https(uri)
  Net::HTTP.new(uri.host, uri.port, *proxy_params).tap do |https|
    https.use_ssl = uri.is_a?(URI::HTTPS)
    if @config.timeout
      https.open_timeout = @config.timeout
      https.read_timeout = @config.timeout
    end
  end
end
build_request(uri, data) click to toggle source
# File lib/airbrake-ruby/sync_sender.rb, line 84
def build_request(uri, data)
  req =
    if @method == :put
      Net::HTTP::Put.new(uri.request_uri)
    else
      Net::HTTP::Post.new(uri.request_uri)
    end

  build_request_body(req, data)
end
build_request_body(req, data) click to toggle source
# File lib/airbrake-ruby/sync_sender.rb, line 95
def build_request_body(req, data)
  req.body = data.to_json

  req['Authorization'] = "Bearer #{@config.project_key}"
  req['Content-Type'] = CONTENT_TYPE
  req['User-Agent'] =
    "#{Airbrake::NOTIFIER_INFO[:name]}/#{Airbrake::AIRBRAKE_RUBY_VERSION} " \
    "Ruby/#{RUBY_VERSION}"

  req
end
handle_rate_limit(parsed_resp) click to toggle source
# File lib/airbrake-ruby/sync_sender.rb, line 107
def handle_rate_limit(parsed_resp)
  return unless parsed_resp.key?('rate_limit_reset')

  @rate_limit_reset = parsed_resp['rate_limit_reset']
end
missing_body?(req, promise) click to toggle source
# File lib/airbrake-ruby/sync_sender.rb, line 133
def missing_body?(req, promise)
  missing = req.body.nil?

  if missing
    reason = "#{LOG_LABEL} data was not sent because of missing body"
    logger.error(reason)
    promise.reject(reason)
  end

  missing
end
proxy_params() click to toggle source
# File lib/airbrake-ruby/sync_sender.rb, line 120
def proxy_params
  return unless @config.proxy.key?(:host)

  [@config.proxy[:host], @config.proxy[:port], @config.proxy[:user],
   @config.proxy[:password]]
end
rate_limited_ip?(promise) click to toggle source
# File lib/airbrake-ruby/sync_sender.rb, line 127
def rate_limited_ip?(promise)
  rate_limited = Time.now < @rate_limit_reset
  promise.reject("#{LOG_LABEL} IP is rate limited") if rate_limited
  rate_limited
end