class HaveAPI::Extensions::ExceptionMailer

This extension mails exceptions raised during action execution and description construction to specified e-mail address.

The template is based on {Sinatra::ShowExceptions::TEMPLATE}, but the JavaScript functions are removed, since e-mail doesn’t support it. HaveAPI-specific content is added. Some helper methods are taken either from Sinatra or Rack.

Constants

Frame
TEMPLATE

Public Class Methods

new(opts) click to toggle source

@param opts [Hash] options @option opts to [String] recipient address @option opts from [String] sender address @option opts subject [String] ‘%s’ is replaced by the error message @option opts smtp [Hash, falsy] smtp options, sendmail is used if not provided

Calls superclass method
# File lib/haveapi/extensions/exception_mailer.rb, line 20
def initialize(opts)
  super()
  @opts = opts
end

Public Instance Methods

enabled(server) click to toggle source
# File lib/haveapi/extensions/exception_mailer.rb, line 25
def enabled(server)
  HaveAPI::Action.connect_hook(:exec_exception) do |ret, context, e|
    log(context, e)
    ret
  end

  server.connect_hook(:description_exception) do |ret, context, e|
    log(context, e)
    ret
  end
end
log(context, exception) click to toggle source
# File lib/haveapi/extensions/exception_mailer.rb, line 37
def log(context, exception)
  req = context.request.request
  path = (req.script_name + req.path_info).squeeze('/')

  frames = exception.backtrace.map do |line|
    frame = Frame.new

    next unless line =~ /(.*?):(\d+)(:in `(.*)')?/

    frame.filename = ::Regexp.last_match(1)
    frame.lineno = ::Regexp.last_match(2).to_i
    frame.function = ::Regexp.last_match(4)

    begin
      lineno = frame.lineno - 1
      lines = ::File.readlines(frame.filename)
      frame.context_line = lines[lineno].chomp
    rescue StandardError
      # ignore
    end

    frame
  end.compact

  env = context.request.env

  user =
    if context.current_user.respond_to?(:id)
      context.current_user.id
    else
      context.current_user
    end

  mail(context, exception, TEMPLATE.result(binding))
end
mail(context, exception, body) click to toggle source
# File lib/haveapi/extensions/exception_mailer.rb, line 73
def mail(context, exception, body)
  mail = ::Mail.new({
    from: @opts[:from],
    to: @opts[:to],
    subject: format(@opts[:subject], exception.to_s),
    body:,
    content_type: 'text/html; charset=UTF-8'
  })

  if @opts[:smtp]
    mail.delivery_method(:smtp, @opts[:smtp])

  else
    mail.delivery_method(:sendmail)
  end

  mail.deliver!
  mail
end

Protected Instance Methods

frame_class(frame) click to toggle source

From {Sinatra::ShowExceptions}

# File lib/haveapi/extensions/exception_mailer.rb, line 96
def frame_class(frame)
  if frame.filename =~ %r{lib/sinatra.*\.rb}
    'framework'
  elsif (defined?(Gem) && frame.filename.include?(Gem.dir)) ||
        frame.filename =~ %r{/bin/(\w+)$}
    'system'
  else
    'app'
  end
end
h(obj) click to toggle source

From {Rack::ShowExceptions}

# File lib/haveapi/extensions/exception_mailer.rb, line 108
def h(obj)
  case obj
  when String
    Rack::Utils.escape_html(obj)
  else
    Rack::Utils.escape_html(obj.inspect)
  end
end