Skip to content

Instantly share code, notes, and snippets.

@sauy7
Created May 5, 2016 13:59
Show Gist options
  • Save sauy7/467a09858771981292778d6efe81d6d9 to your computer and use it in GitHub Desktop.
Save sauy7/467a09858771981292778d6efe81d6d9 to your computer and use it in GitHub Desktop.
Adding support for creating GitHub issues with Exception Notification gem in Rails
gem 'octokit', ~> '4.3.0'
# lib/exception_notifier/github_notifier.rb
require 'action_dispatch'
require 'octokit'
require 'pp'
module ExceptionNotifier
class GithubNotifier < BaseNotifier
class MissingController
def method_missing(*args, &block)
end
end
def initialize(options)
super
@default_options = options
end
def call(exception, options={})
@env = options[:env]
@exception = exception
@kontroller = @env['action_controller.instance'] || MissingController.new
options = options.reverse_merge(@default_options)
@exception = { error_class: exception.class.to_s,
message: exception.message.inspect,
backtrace: exception.backtrace }
@data = (@env && @env['exception_notifier.exception_data'] || {}).merge(options[:data] || {})
unless @env.nil?
@request = ActionDispatch::Request.new(@env)
@request_items = { url: @request.original_url,
http_method: @request.method,
ip_address: @request.remote_ip,
parameters: @request.filtered_parameters,
timestamp: Time.current }
@session = @request.session
@environment = @request.filtered_env
end
issue_options = {
login: options.delete(:login),
password: options.delete(:password),
repo: options.delete(:repo),
title: compose_title(options.delete(:prefix)),
body: compose_body
}
send_notice(@exception, options, nil, issue_options) do |_msg, opts|
client = Octokit::Client.new(login: opts[:login], password: opts[:password])
client.create_issue(opts[:repo], opts[:title], opts[:body])
end
end
private
def compose_backtrace_section
return '' if @exception[:backtrace].empty?
out = sub_title('Backtrace')
out << "<pre>#{@exception[:backtrace].join("\n")}</pre>\n"
end
def compose_body
body = compose_header
if @env.nil?
body << compose_backtrace_section
else
body << compose_request_section
body << compose_session_section
body << compose_environment_section
body << compose_backtrace_section
end
body << compose_data_section
end
def compose_data_section
return '' if @data.empty?
out = sub_title('Data')
out << "`#{PP.pp(@data, '')}`\n"
end
def compose_environment_section
out = sub_title('Environment')
max = @environment.keys.map(&:to_s).max { |a, b| a.length <=> b.length }
@environment.keys.map(&:to_s).sort.each do |key|
out << "* `#{"%-*s: %s" % [max.length, key, inspect_object(@environment[key])]}`\n"
end
out << "\n"
end
def compose_header
header = @exception.class.to_s =~ /^[aeiou]/i ? 'An' : 'A'
header << format(" %s occurred in %s#%s:\n\n",
@exception[:error_class],
@kontroller.controller_name,
@kontroller.action_name)
header << "`#{@exception[:message]}\n"
header << "#{@exception[:backtrace].first}`\n\n"
end
def compose_request_section
return '' if @request_items.empty?
out = sub_title('Request')
out << "* URL : `#{@request_items[:url]}`\n"
out << "* HTTP Method: `#{@request_items[:http_method]}`\n"
out << "* IP address : `#{@request_items[:ip_address]}`\n"
out << "* Parameters : `#{@request_items[:parameters].inspect}`\n"
out << "* Timestamp : `#{@request_items[:timestamp]}`\n"
out << "* Server : `#{Socket.gethostname}`\n"
if defined?(Rails) && Rails.respond_to?(:root)
out << "* Rails root : `#{Rails.root}`"
end
out << "* Process : `#{$$}`\n"
end
def compose_session_section
out = sub_title('Session')
id = if @request.ssl?
out << "[FILTERED]"
else
rack_session_id = (@request.env["rack.session.options"] and @request.env["rack.session.options"][:id])
(@request.session['session_id'] || rack_session_id).inspect
end
out << format("* session id: `%s`\n", id)
out << "* data: `#{PP.pp(@request.session.to_hash, '')}`\n"
end
def compose_title(prefix = '[Error]')
subject = "#{prefix} "
subject << "#{@kontroller.controller_name}##{@kontroller.action_name}" if @kontroller
subject << " (#{@exception.class})"
subject.length > 120 ? subject[0...120] + "..." : subject
end
def inspect_object(object)
case object
when Hash, Array
object.inspect
else
object.to_s
end
end
def sub_title(text)
"## #{text}:\n\n"
end
end
end
# config/environment/production.rb
config.middleware.use ExceptionNotification::Rack,
github: {
prefix: '[CUSTOM ISSUE TITLE PREFIX]',
repo: 'Owner/project',
login: ENV['GITHUB_LOGIN'],
password: ENV['GITHUB_PASSWORD']
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment