Created
May 5, 2016 13:59
-
-
Save sauy7/467a09858771981292778d6efe81d6d9 to your computer and use it in GitHub Desktop.
Adding support for creating GitHub issues with Exception Notification gem in Rails
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
gem 'octokit', ~> '4.3.0' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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