1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
|
# frozen_string_literal: true
module ExceptionNotifier
class SnsNotifier < BaseNotifier
def initialize(options)
super
raise ArgumentError, "You must provide 'region' option" unless options[:region]
raise ArgumentError, "You must provide 'access_key_id' option" unless options[:access_key_id]
raise ArgumentError, "You must provide 'secret_access_key' option" unless options[:secret_access_key]
@notifier = Aws::SNS::Client.new(
region: options[:region],
access_key_id: options[:access_key_id],
secret_access_key: options[:secret_access_key]
)
@options = default_options.merge(options)
end
def call(exception, custom_opts = {})
custom_options = options.merge(custom_opts)
subject = build_subject(exception, custom_options)
message = build_message(exception, custom_options)
notifier.publish(
topic_arn: custom_options[:topic_arn],
message: message,
subject: subject
)
end
private
attr_reader :notifier, :options
def build_subject(exception, options)
subject =
"#{options[:sns_prefix]} - #{accumulated_exception_name(exception, options)} occurred"
(subject.length > 120) ? subject[0...120] + "..." : subject
end
def build_message(exception, options)
exception_name = accumulated_exception_name(exception, options)
if options[:env].nil?
text = "#{exception_name} occured in background\n"
data = options[:data] || {}
else
env = options[:env]
kontroller = env["action_controller.instance"]
data = (env["exception_notifier.exception_data"] || {}).merge(options[:data] || {})
request = "#{env["REQUEST_METHOD"]} <#{env["REQUEST_URI"]}>"
text = "#{exception_name} occurred while #{request}"
text += " was processed by #{kontroller.controller_name}##{kontroller.action_name}\n" if kontroller
end
text += "Exception: #{exception.message}\n"
text += "Hostname: #{Socket.gethostname}\n"
text += "Data: #{data}\n"
return unless exception.backtrace
formatted_backtrace = exception.backtrace.first(options[:backtrace_lines]).join("\n").to_s
text + "Backtrace:\n#{formatted_backtrace}\n"
end
def accumulated_exception_name(exception, options)
errors_count = options[:accumulated_errors_count].to_i
measure_word = if errors_count > 1
errors_count
else
/^[aeiou]/i.match?(exception.class.to_s) ? "An" : "A"
end
"#{measure_word} #{exception.class}"
end
def default_options
{
sns_prefix: "[ERROR]",
backtrace_lines: 10
}
end
end
end
|