forked from rails/exception_notification
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Use formatter in Mattermost notifier
- Loading branch information
1 parent
536f89b
commit 1d9db20
Showing
6 changed files
with
88 additions
and
150 deletions.
There are no files selected for viewing
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,163 +1,75 @@ | ||
require 'action_dispatch' | ||
require 'active_support/core_ext/time' | ||
require 'httparty' | ||
|
||
module ExceptionNotifier | ||
class MattermostNotifier | ||
include ExceptionNotifier::BacktraceCleaner | ||
|
||
class MissingController | ||
def method_missing(*args, &block); end | ||
end | ||
|
||
attr_accessor :httparty | ||
|
||
def initialize(options = {}) | ||
super() | ||
@default_options = options | ||
@httparty = HTTParty | ||
end | ||
|
||
class MattermostNotifier < BaseNotifier | ||
def call(exception, options = {}) | ||
@options = options.merge(@default_options) | ||
@options = options.merge(base_options) | ||
@exception = exception | ||
@backtrace = exception.backtrace ? clean_backtrace(exception) : nil | ||
|
||
@env = @options.delete(:env) | ||
@formatter = Formatter.new( | ||
exception, | ||
env: @options.delete(:env), | ||
app_name: @options.delete(:app_name), | ||
accumulated_errors_count: @options[:accumulated_errors_count] | ||
) | ||
|
||
@application_name = @options.delete(:app_name) || Rails.application.class.parent_name.underscore | ||
avatar = @options.delete(:avatar) | ||
channel = @options.delete(:channel) | ||
@gitlab_url = @options.delete(:git_url) | ||
@username = @options.delete(:username) || 'Exception Notifier' | ||
@avatar = @options.delete(:avatar) | ||
|
||
@channel = @options.delete(:channel) | ||
@webhook_url = @options.delete(:webhook_url) | ||
raise ArgumentError, "You must provide 'webhook_url' parameter." unless @webhook_url | ||
|
||
if @env.nil? | ||
@controller = @request_items = nil | ||
else | ||
@controller = @env['action_controller.instance'] || MissingController.new | ||
|
||
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 } | ||
|
||
if request.session['warden.user.user.key'] | ||
current_user = User.find(request.session['warden.user.user.key'][0][0]) | ||
@request_items[:current_user] = { id: current_user.id, email: current_user.email } | ||
end | ||
end | ||
|
||
payload = message_text.merge(user_info).merge(channel_info) | ||
payload = { | ||
text: message_text.compact.join("\n") | ||
} | ||
payload[:username] = @options.delete(:username) || 'Exception Notifier' | ||
payload[:icon_url] = avatar if avatar | ||
payload[:channel] = channel if channel | ||
|
||
@options[:body] = payload.to_json | ||
@options[:headers] ||= {} | ||
@options[:headers]['Content-Type'] = 'application/json' | ||
|
||
@httparty.post(@webhook_url, @options) | ||
HTTParty.post(@webhook_url, @options) | ||
end | ||
|
||
private | ||
|
||
def channel_info | ||
if @channel | ||
{ channel: @channel } | ||
else | ||
{} | ||
end | ||
end | ||
|
||
def user_info | ||
infos = {} | ||
|
||
infos[:username] = @username if @username | ||
infos[:icon_url] = @avatar if @avatar | ||
|
||
infos | ||
end | ||
attr_reader :formatter | ||
|
||
def message_text | ||
text = [] | ||
|
||
text += ['@channel'] | ||
text += message_header | ||
text += message_request if @request_items | ||
text += message_backtrace if @backtrace | ||
text += message_issue_link if @gitlab_url | ||
|
||
{ text: text.join("\n") } | ||
end | ||
|
||
def message_header | ||
text = [] | ||
|
||
errors_count = @options[:accumulated_errors_count].to_i | ||
text << "### :warning: Error 500 in #{Rails.env} :warning:" | ||
text << "#{errors_count > 1 ? errors_count : 'An'} *#{@exception.class}* occured" + (@controller ? " in *#{controller_and_method}*." : '.') | ||
text << "*#{@exception.message}*" | ||
|
||
text | ||
end | ||
|
||
def message_request | ||
text = [] | ||
|
||
text << '### Request' | ||
text << '```' | ||
text << hash_presentation(@request_items) | ||
text << '```' | ||
|
||
text | ||
end | ||
text = [ | ||
'@channel', | ||
"### #{formatter.title}", | ||
formatter.subtitle, | ||
"*#{@exception.message}*" | ||
] | ||
|
||
if (request = formatter.request_message.presence) | ||
text << '### Request' | ||
text << request | ||
end | ||
|
||
def message_backtrace(size = 3) | ||
text = [] | ||
if (backtrace = formatter.backtrace_message.presence) | ||
text << '### Backtrace' | ||
text << backtrace | ||
end | ||
|
||
size = @backtrace.size < size ? @backtrace.size : size | ||
text << '### Backtrace' | ||
text << '```' | ||
size.times { |i| text << '* ' + @backtrace[i] } | ||
text << '```' | ||
text << message_issue_link if @gitlab_url | ||
|
||
text | ||
end | ||
|
||
def message_issue_link | ||
text = [] | ||
|
||
link = [@gitlab_url, @application_name, 'issues', 'new'].join('/') | ||
link = [@gitlab_url, formatter.app_name, 'issues', 'new'].join('/') | ||
params = { | ||
'issue[title]' => ['[BUG] Error 500 :', | ||
controller_and_method, | ||
formatter.controller_and_action || '', | ||
"(#{@exception.class})", | ||
@exception.message].compact.join(' ') | ||
}.to_query | ||
|
||
text << "[Create an issue](#{link}/?#{params})" | ||
|
||
text | ||
end | ||
|
||
def controller_and_method | ||
if @controller | ||
"#{@controller.controller_name}##{@controller.action_name}" | ||
else | ||
'' | ||
end | ||
end | ||
|
||
def hash_presentation(hash) | ||
text = [] | ||
|
||
hash.each do |key, value| | ||
text << "* #{key} : #{value}" | ||
end | ||
|
||
text.join("\n") | ||
"[Create an issue](#{link}/?#{params})" | ||
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
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
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