Hello community,
here is the log from the commit of package rubygem-exception_notification for
openSUSE:Factory checked in at 2019-01-21 10:25:53
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/rubygem-exception_notification (Old)
and /work/SRC/openSUSE:Factory/.rubygem-exception_notification.new.28833
(New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "rubygem-exception_notification"
Mon Jan 21 10:25:53 2019 rev:18 rq:656380 version:4.3.0
Changes:
--------
---
/work/SRC/openSUSE:Factory/rubygem-exception_notification/rubygem-exception_notification.changes
2017-09-04 12:36:55.882372182 +0200
+++
/work/SRC/openSUSE:Factory/.rubygem-exception_notification.new.28833/rubygem-exception_notification.changes
2019-01-21 10:25:55.561712878 +0100
@@ -1,0 +2,21 @@
+Sat Dec 8 16:20:42 UTC 2018 - Stephan Kulow <[email protected]>
+
+- updated to version 4.3.0
+ see installed CHANGELOG.rdoc
+
+ == 4.3.0
+
+ * enhancements
+ * Add Microsoft Teams Notifier (by @phaelin)
+ * Add SNS notifier (by @FLarra)
+ * Add Google Chats notifier (by @renatolond)
+ * Align output of section-headers consistently (by @kronn)
+ * ExceptionNotifier.notify_exception receives block & pass it to each
notifier (by @pocke)
+ * Update Travis to latest rubies (by @lostapathy)
+
+ * bug fixes
+ * Replace all before_filter to before_action on readme (by @pastullo)
+ * Fix error when using error grouping outside of rails (by @garethcokell)
+ * Fix missing MissingController Mattermost class (by @n-rodriguez)
+
+-------------------------------------------------------------------
Old:
----
exception_notification-4.2.2.gem
New:
----
exception_notification-4.3.0.gem
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ rubygem-exception_notification.spec ++++++
--- /var/tmp/diff_new_pack.002CIj/_old 2019-01-21 10:25:56.913711393 +0100
+++ /var/tmp/diff_new_pack.002CIj/_new 2019-01-21 10:25:56.913711393 +0100
@@ -1,7 +1,7 @@
#
# spec file for package rubygem-exception_notification
#
-# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -12,7 +12,7 @@
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.
-# Please submit bugfixes or comments via http://bugs.opensuse.org/
+# Please submit bugfixes or comments via https://bugs.opensuse.org/
#
@@ -24,7 +24,7 @@
#
Name: rubygem-exception_notification
-Version: 4.2.2
+Version: 4.3.0
Release: 0
%define mod_name exception_notification
%define mod_full_name %{mod_name}-%{version}
@@ -33,7 +33,7 @@
BuildRequires: %{rubygem gem2rpm}
BuildRequires: ruby-macros >= 5
Url: https://smartinez87.github.io/exception_notification/
-Source: http://rubygems.org/gems/%{mod_full_name}.gem
+Source: https://rubygems.org/gems/%{mod_full_name}.gem
Source1: gem2rpm.yml
Summary: Exception notification for Rails apps
License: MIT
++++++ exception_notification-4.2.2.gem -> exception_notification-4.3.0.gem
++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/Appraisals new/Appraisals
--- old/Appraisals 2017-08-12 22:52:29.000000000 +0200
+++ new/Appraisals 2018-11-22 23:02:26.000000000 +0100
@@ -1,8 +1,7 @@
-rails_versions = ['~> 4.0.5', '~> 4.1.1', '~> 4.2.0', '~> 5.0.0']
+rails_versions = ['~> 4.0.5', '~> 4.1.1', '~> 4.2.0', '~> 5.0.0', '~> 5.1.0']
rails_versions.each do |rails_version|
appraise "rails#{rails_version.slice(/\d+\.\d+/).gsub('.', '_')}" do
gem 'rails', rails_version
- gem "sqlite3"
end
end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/CHANGELOG.rdoc new/CHANGELOG.rdoc
--- old/CHANGELOG.rdoc 2017-08-12 22:52:29.000000000 +0200
+++ new/CHANGELOG.rdoc 2018-11-22 23:02:26.000000000 +0100
@@ -1,7 +1,22 @@
+== 4.3.0
+
+* enhancements
+ * Add Microsoft Teams Notifier (by @phaelin)
+ * Add SNS notifier (by @FLarra)
+ * Add Google Chats notifier (by @renatolond)
+ * Align output of section-headers consistently (by @kronn)
+ * ExceptionNotifier.notify_exception receives block & pass it to each
notifier (by @pocke)
+ * Update Travis to latest rubies (by @lostapathy)
+
+* bug fixes
+ * Replace all before_filter to before_action on readme (by @pastullo)
+ * Fix error when using error grouping outside of rails (by @garethcokell)
+ * Fix missing MissingController Mattermost class (by @n-rodriguez)
+
== 4.2.2
* enhancements
- * Error groupiong (by @Martin91)
+ * Error grouping (by @Martin91)
* Additional fields for Slack support (by @schurig)
* Enterprise HipChat support (by @seanhuber)
@@ -131,7 +146,7 @@
* Add normalize_subject option to remove numbers from email so that they
thread (by @jjb)
* Allow the user to provide a custom message and hash of data (by @jjb)
* Add support for configurable background sections and a data partial (by
@jeffrafter)
- * Include timestamp of exception in notification body
+ * Include timestamp of exception in notification body
* Add support for rack based session management (by @phoet)
* Add ignore_crawlers option to ignore exceptions generated by crawlers
* Add verbode_subject option to exclude exception message from subject (by
@amishyn)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/README.md new/README.md
--- old/README.md 2017-08-12 22:52:29.000000000 +0200
+++ new/README.md 2018-11-22 23:02:26.000000000 +0100
@@ -9,7 +9,7 @@
---
-The Exception Notification gem provides a set of [notifiers](#notifiers) for
sending notifications when errors occur in a Rack/Rails application. The
built-in notifiers can deliver notifications by [email](#email-notifier),
[Campfire](#campfire-notifier), [HipChat](#hipchat-notifier),
[Slack](#slack-notifier), [Mattermost](#mattermost-notifier),
[IRC](#irc-notifier) or via custom [WebHooks](#webhook-notifier).
+The Exception Notification gem provides a set of [notifiers](#notifiers) for
sending notifications when errors occur in a Rack/Rails application. The
built-in notifiers can deliver notifications by [email](#email-notifier),
[Campfire](#campfire-notifier), [HipChat](#hipchat-notifier),
[Slack](#slack-notifier), [Mattermost](#mattermost-notifier),
[Teams](#teams-notifier), [IRC](#irc-notifier), [Amazon
SNS](#amazon-sns-notifier), [Google Chat](#google-chat-notifier) or via custom
[WebHooks](#webhook-notifier).
There's a great [Railscast about Exception
Notification](http://railscasts.com/episodes/104-exception-notifications-revised)
you can see that may help you getting started.
@@ -56,7 +56,7 @@
```ruby
class ApplicationController < ActionController::Base
- before_filter :prepare_exception_notifier
+ before_action :prepare_exception_notifier
private
def prepare_exception_notifier
request.env["exception_notifier.exception_data"] = {
@@ -90,6 +90,9 @@
* [IRC notifier](#irc-notifier)
* [Slack notifier](#slack-notifier)
* [Mattermost notifier](#mattermost-notifier)
+* [Teams notifier](#teams-notifier)
+* [Amazon SNS](#amazon-sns-notifier)
+* [Google Chat notifier](#google-chat-notifier)
* [WebHook notifier](#webhook-notifier)
But, you also can easily implement your own [custom
notifier](#custom-notifier).
@@ -220,7 +223,7 @@
```ruby
class ApplicationController < ActionController::Base
- before_filter :log_additional_data
+ before_action :log_additional_data
...
protected
def log_additional_data
@@ -542,7 +545,7 @@
An example of how to send the server name to Slack in Rails (put this code in
application_controller.rb):
```ruby
-before_filter :set_notification
+before_action :set_notification
def set_notification
request.env['exception_notifier.exception_data'] = {"server" =>
request.env['SERVER_NAME']}
@@ -608,7 +611,7 @@
Contains additional fields that will be added to the attachement. See [Slack
documentation](https://api.slack.com/docs/message-attachments).
-## Mattermost notifier
+### Mattermost notifier
Post notification in a mattermost channel via [incoming
webhook](http://docs.mattermost.com/developer/webhooks-incoming.html)
@@ -723,6 +726,128 @@
Your application name used for issue creation link. Defaults to ```
Rails.application.class.parent_name.underscore```.
+### Google Chat Notifier
+
+Post notifications in a Google Chats channel via [incoming
webhook](https://developers.google.com/hangouts/chat/how-tos/webhooks)
+
+Add the [HTTParty](https://github.com/jnunemaker/httparty) gem to your
`Gemfile`:
+
+```ruby
+gem 'httparty'
+```
+
+To configure it, you **need** to set the `webhook_url` option.
+
+```ruby
+Rails.application.config.middleware.use ExceptionNotification::Rack,
+ :google_chat => {
+ :webhook_url =>
'https://chat.googleapis.com/v1/spaces/XXXXXXXX/messages?key=YYYYYYYYYYYYY&token=ZZZZZZZZZZZZ'
+ }
+```
+
+##### webhook_url
+
+*String, required*
+
+The Incoming WebHook URL on Google Chats.
+
+##### app_name
+
+*String, optional*
+
+Your application name, shown in the notification. Defaults to
`Rails.application.class.parent_name.underscore`.
+
+### Amazon SNS Notifier
+
+Notify all exceptions Amazon - Simple Notification Service:
[SNS](https://aws.amazon.com/sns/).
+
+#### Usage
+
+Add the
[aws-sdk-sns](https://github.com/aws/aws-sdk-ruby/tree/master/gems/aws-sdk-sns)
gem to your `Gemfile`:
+
+```ruby
+ gem 'aws-sdk-sns', '~> 1.5'
+```
+
+To configure it, you **need** to set 3 required options for aws: `region`,
`access_key_id` and `secret_access_key`, and one more option for sns:
`topic_arn`.
+
+```ruby
+Rails.application.config.middleware.use ExceptionNotification::Rack,
+ sns: {
+ region: 'us-east-x',
+ access_key_id: 'access_key_id',
+ secret_access_key: 'secret_access_key',
+ topic_arn: 'arn:aws:sns:us-east-x:XXXX:my-topic'
+ }
+```
+
+##### sns_prefix
+*String, optional *
+
+Prefix in the notification subject, by default: "[Error]"
+
+##### backtrace_lines
+*Integer, optional *
+
+Number of backtrace lines to be displayed in the notification message. By
default: 10
+
+#### Note:
+* You may need to update your previous `aws-sdk-*` gems in order to setup
`aws-sdk-sns` correctly.
+* If you need any further information about the available regions or any other
SNS related topic consider: [SNS faqs](https://aws.amazon.com/sns/faqs/)
+
+### Teams notifier
+
+Post notification in a Microsoft Teams channel via [Incoming Webhook
Connector](https://docs.microsoft.com/en-us/outlook/actionable-messages/actionable-messages-via-connectors)
+Just add the [HTTParty](https://github.com/jnunemaker/httparty) gem to your
`Gemfile`:
+
+```ruby
+gem 'httparty'
+```
+
+To configure it, you **need** to set the `webhook_url` option.
+If you are using GitLab for issue tracking, you can specify `git_url` as
follows to add a *Create issue* button in your notification.
+By default this will use your Rails application name to match the git
repository. If yours differs, you can specify `app_name`.
+By that same notion, you may also set a `jira_url` to get a button that will
send you to the New Issue screen in Jira.
+
+```ruby
+Rails.application.config.middleware.use ExceptionNotification::Rack,
+ :email => {
+ :email_prefix => "[PREFIX] ",
+ :sender_address => %{"notifier" <[email protected]>},
+ :exception_recipients => %w{[email protected]}
+ },
+ :teams => {
+ :webhook_url =>
'https://outlook.office.com/webhook/your-guid/IncomingWebhook/team-guid',
+ :git_url => 'https://your-gitlab.com/Group/Project',
+ :jira_url => 'https://your-jira.com'
+ }
+```
+
+#### Options
+
+##### webhook_url
+
+*String, required*
+
+The Incoming WebHook URL on mattermost.
+
+##### git_url
+
+*String, optional*
+
+Url of your gitlab or github with your organisation name for issue creation
link (Eg: `github.com/aschen`). Defaults to nil and doesn't add link to the
notification.
+
+##### jira_url
+
+*String, optional*
+
+Url of your Jira instance, adds button for Create Issue screen. Defaults to
nil and doesn't add a button to the card.
+
+##### app_name
+
+*String, optional*
+
+Your application name used for git issue creation link. Defaults to
`Rails.application.class.parent_name.underscore`.
### WebHook notifier
Binary files old/checksums.yaml.gz and new/checksums.yaml.gz differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/exception_notification.gemspec
new/exception_notification.gemspec
--- old/exception_notification.gemspec 2017-08-12 22:52:29.000000000 +0200
+++ new/exception_notification.gemspec 2018-11-22 23:02:26.000000000 +0100
@@ -1,8 +1,8 @@
Gem::Specification.new do |s|
s.name = 'exception_notification'
- s.version = '4.2.2'
+ s.version = '4.3.0'
s.authors = ["Jamis Buck", "Josh Peek"]
- s.date = %q{2017-08-12}
+ s.date = %q{2018-11-22}
s.summary = "Exception notification for Rails apps"
s.homepage = "https://smartinez87.github.io/exception_notification/"
s.email = "[email protected]"
@@ -32,4 +32,5 @@
s.add_development_dependency "hipchat", ">= 1.0.0"
s.add_development_dependency "carrier-pigeon", ">= 0.7.0"
s.add_development_dependency "slack-notifier", ">= 1.0.0"
+ s.add_development_dependency "aws-sdk-sns", "~> 1"
end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/gemfiles/rails4_0.gemfile
new/gemfiles/rails4_0.gemfile
--- old/gemfiles/rails4_0.gemfile 2017-08-12 22:52:29.000000000 +0200
+++ new/gemfiles/rails4_0.gemfile 2018-11-22 23:02:26.000000000 +0100
@@ -3,6 +3,5 @@
source "https://rubygems.org"
gem "rails", "~> 4.0.5"
-gem "sqlite3"
gemspec :path => "../"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/gemfiles/rails4_1.gemfile
new/gemfiles/rails4_1.gemfile
--- old/gemfiles/rails4_1.gemfile 2017-08-12 22:52:29.000000000 +0200
+++ new/gemfiles/rails4_1.gemfile 2018-11-22 23:02:26.000000000 +0100
@@ -3,6 +3,5 @@
source "https://rubygems.org"
gem "rails", "~> 4.1.1"
-gem "sqlite3"
gemspec :path => "../"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/gemfiles/rails4_2.gemfile
new/gemfiles/rails4_2.gemfile
--- old/gemfiles/rails4_2.gemfile 2017-08-12 22:52:29.000000000 +0200
+++ new/gemfiles/rails4_2.gemfile 2018-11-22 23:02:26.000000000 +0100
@@ -3,6 +3,5 @@
source "https://rubygems.org"
gem "rails", "~> 4.2.0"
-gem "sqlite3"
gemspec :path => "../"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/gemfiles/rails5_0.gemfile
new/gemfiles/rails5_0.gemfile
--- old/gemfiles/rails5_0.gemfile 2017-08-12 22:52:29.000000000 +0200
+++ new/gemfiles/rails5_0.gemfile 2018-11-22 23:02:26.000000000 +0100
@@ -3,6 +3,5 @@
source "https://rubygems.org"
gem "rails", "~> 5.0.0"
-gem "sqlite3"
gemspec :path => "../"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/gemfiles/rails5_1.gemfile
new/gemfiles/rails5_1.gemfile
--- old/gemfiles/rails5_1.gemfile 1970-01-01 01:00:00.000000000 +0100
+++ new/gemfiles/rails5_1.gemfile 2018-11-22 23:02:26.000000000 +0100
@@ -0,0 +1,7 @@
+# This file was generated by Appraisal
+
+source "https://rubygems.org"
+
+gem "rails", "~> 5.1.0"
+
+gemspec :path => "../"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/lib/exception_notifier/email_notifier.rb
new/lib/exception_notifier/email_notifier.rb
--- old/lib/exception_notifier/email_notifier.rb 2017-08-12
22:52:29.000000000 +0200
+++ new/lib/exception_notifier/email_notifier.rb 2018-11-22
23:02:26.000000000 +0100
@@ -60,8 +60,8 @@
def compose_subject
subject = "#{@options[:email_prefix]}"
- subject << "(#{@options[:accumulated_errors_count]} times) " if
@options[:accumulated_errors_count].to_i > 1
- subject <<
"#{@kontroller.controller_name}##{@kontroller.action_name}" if @kontroller &&
@options[:include_controller_and_action_names_in_subject]
+ subject << "(#{@options[:accumulated_errors_count]} times)" if
@options[:accumulated_errors_count].to_i > 1
+ subject << "#{@kontroller.controller_name}
#{@kontroller.action_name}" if @kontroller &&
@options[:include_controller_and_action_names_in_subject]
subject << " (#{@exception.class})"
subject << " #{@exception.message.inspect}" if
@options[:verbose_subject]
subject = EmailNotifier.normalize_digits(subject) if
@options[:normalize_subject]
@@ -75,17 +75,17 @@
end
helper_method :inspect_object
-
+
def truncate(string, max)
string.length > max ? "#{string[0...max]}..." : string
end
-
+
def inspect_object(object)
case object
when Hash, Array
truncate(object.inspect, 300)
else
- object.to_s
+ object.to_s
end
end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/lib/exception_notifier/google_chat_notifier.rb
new/lib/exception_notifier/google_chat_notifier.rb
--- old/lib/exception_notifier/google_chat_notifier.rb 1970-01-01
01:00:00.000000000 +0100
+++ new/lib/exception_notifier/google_chat_notifier.rb 2018-11-22
23:02:26.000000000 +0100
@@ -0,0 +1,136 @@
+require 'action_dispatch'
+require 'active_support/core_ext/time'
+
+module ExceptionNotifier
+ class GoogleChatNotifier
+ 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
+
+ def call(exception, options = {})
+ @options = options.merge(@default_options)
+ @exception = exception
+ @backtrace = exception.backtrace ? clean_backtrace(exception) : nil
+
+ @env = @options.delete(:env)
+
+ @application_name = @options.delete(:app_name) ||
Rails.application.class.parent_name.underscore
+
+ @webhook_url = @options.delete(:webhook_url)
+ raise ArgumentError.new "You must provide 'webhook_url' parameter."
unless @webhook_url
+
+ unless @env.nil?
+ @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 }
+ else
+ @controller = @request_items = nil
+ end
+
+
+ @options[:body] = payload.to_json
+ @options[:headers] ||= {}
+ @options[:headers].merge!({ 'Content-Type' => 'application/json' })
+
+ @httparty.post(@webhook_url, @options)
+ end
+
+ private
+
+ def payload
+ {
+ text: exception_text
+ }
+ end
+
+ def header
+ errors_count = @options[:accumulated_errors_count].to_i
+ text = ['']
+
+ text << "Application: *#{@application_name}*"
+ text << "#{errors_count > 1 ? errors_count : 'An'} *#{@exception.class}*
occured" + if @controller then " in *#{controller_and_method}*." else "." end
+
+ text
+ end
+
+ def exception_text
+ text = []
+
+ text << header
+ text << ''
+
+ text << "⚠️ Error 500 in #{Rails.env} ⚠️"
+ text << "*#{@exception.message.gsub('`', %q('))}*"
+
+ if @request_items
+ text << ''
+ text += message_request
+ end
+
+ if @backtrace
+ text << ''
+ text += message_backtrace
+ end
+
+ text.join("\n")
+ end
+
+ def message_request
+ text = []
+
+ text << "*Request:*"
+ text << "```"
+ text << hash_presentation(@request_items)
+ text << "```"
+
+ text
+ end
+
+ def hash_presentation(hash)
+ text = []
+
+ hash.each do |key, value|
+ text << "* #{key} : #{value}"
+ end
+
+ text.join("\n")
+ end
+
+ def message_backtrace(size = 3)
+ text = []
+
+ size = @backtrace.size < size ? @backtrace.size : size
+ text << "*Backtrace:*"
+ text << "```"
+ size.times { |i| text << "* " + @backtrace[i] }
+ text << "```"
+
+ text
+ end
+
+ def controller_and_method
+ if @controller
+ "#{@controller.controller_name}##{@controller.action_name}"
+ else
+ ""
+ end
+ end
+ end
+end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/lib/exception_notifier/mattermost_notifier.rb
new/lib/exception_notifier/mattermost_notifier.rb
--- old/lib/exception_notifier/mattermost_notifier.rb 2017-08-12
22:52:29.000000000 +0200
+++ new/lib/exception_notifier/mattermost_notifier.rb 2018-11-22
23:02:26.000000000 +0100
@@ -5,6 +5,11 @@
class MattermostNotifier
include ExceptionNotifier::BacktraceCleaner
+ class MissingController
+ def method_missing(*args, &block)
+ end
+ end
+
attr_accessor :httparty
def initialize(options = {})
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/lib/exception_notifier/modules/error_grouping.rb
new/lib/exception_notifier/modules/error_grouping.rb
--- old/lib/exception_notifier/modules/error_grouping.rb 2017-08-12
22:52:29.000000000 +0200
+++ new/lib/exception_notifier/modules/error_grouping.rb 2018-11-22
23:02:26.000000000 +0100
@@ -52,7 +52,7 @@
else
backtrace_based_key =
"exception:#{Zlib.crc32("#{exception.class.name}\npath:#{exception.backtrace.try(:first)}")}"
- if count = Rails.cache.read(backtrace_based_key)
+ if count = error_grouping_cache.read(backtrace_based_key)
accumulated_errors_count = count + 1
save_error_count(backtrace_based_key, accumulated_errors_count)
else
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/lib/exception_notifier/sns_notifier.rb
new/lib/exception_notifier/sns_notifier.rb
--- old/lib/exception_notifier/sns_notifier.rb 1970-01-01 01:00:00.000000000
+0100
+++ new/lib/exception_notifier/sns_notifier.rb 2018-11-22 23:02:26.000000000
+0100
@@ -0,0 +1,79 @@
+module ExceptionNotifier
+ class SnsNotifier < BaseNotifier
+ def initialize(options)
+ super
+
+ raise ArgumentError.new "You must provide 'region' option" unless
options[:region]
+ raise ArgumentError.new "You must provide 'access_key_id' option" unless
options[:access_key_id]
+ raise ArgumentError.new "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]} - "
+ subject << accumulated_exception_name(exception, options)
+ subject << " 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"
+ else
+ env = options[:env]
+
+ kontroller = env['action_controller.instance']
+ 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"
+
+ if exception.backtrace
+ formatted_backtrace =
"#{exception.backtrace.first(options[:backtrace_lines]).join("\n")}"
+ text += "Backtrace:\n#{formatted_backtrace}\n"
+ end
+ end
+
+ def accumulated_exception_name(exception, options)
+ errors_count = options[:accumulated_errors_count].to_i
+ measure_word = errors_count > 1 ? errors_count : (exception.class.to_s
=~ /^[aeiou]/i ? 'An' : 'A')
+ "#{measure_word} #{exception.class.to_s}"
+ end
+
+ def default_options
+ {
+ sns_prefix: '[ERROR]',
+ backtrace_lines: 10
+ }
+ end
+ end
+end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/lib/exception_notifier/teams_notifier.rb
new/lib/exception_notifier/teams_notifier.rb
--- old/lib/exception_notifier/teams_notifier.rb 1970-01-01
01:00:00.000000000 +0100
+++ new/lib/exception_notifier/teams_notifier.rb 2018-11-22
23:02:26.000000000 +0100
@@ -0,0 +1,179 @@
+require 'action_dispatch'
+require 'active_support/core_ext/time'
+
+module ExceptionNotifier
+ class TeamsNotifier < BaseNotifier
+ 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
+
+ def call(exception, options={})
+ @options = options.merge(@default_options)
+ @exception = exception
+ @backtrace = exception.backtrace ? clean_backtrace(exception) : nil
+
+ @env = @options.delete(:env)
+
+ @application_name = @options.delete(:app_name) ||
Rails.application.class.parent_name.underscore
+ @gitlab_url = @options.delete(:git_url)
+ @jira_url = @options.delete(:jira_url)
+
+ @webhook_url = @options.delete(:webhook_url)
+ raise ArgumentError.new "You must provide 'webhook_url' parameter."
unless @webhook_url
+
+ unless @env.nil?
+ @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.merge!({ current_user: { id: current_user.id, email:
current_user.email } })
+ end
+ else
+ @controller = @request_items = nil
+ end
+
+ payload = message_text
+
+ @options[:body] = payload.to_json
+ @options[:headers] ||= {}
+ @options[:headers].merge!({ 'Content-Type' => 'application/json' })
+ @options[:debug_output] = $stdout
+
+ @httparty.post(@webhook_url, @options)
+ end
+
+ private
+
+ def message_text
+ errors_count = @options[:accumulated_errors_count].to_i
+
+ text = {
+ "@type" => "MessageCard",
+ "@context" => "http://schema.org/extensions",
+ "summary" => "#{@application_name} Exception Alert",
+ "title" => "⚠️ Exception Occurred in #{Rails.env} ⚠️",
+ "sections" => [
+ {
+ "activityTitle" => "#{errors_count > 1 ? errors_count : 'A'}
*#{@exception.class}* occurred" + if @controller then " in
*#{controller_and_method}*." else "." end,
+ "activitySubtitle" => "#{@exception.message}"
+ }
+ ],
+ "potentialAction" => []
+ }
+
+ text['sections'].push details
+ text['potentialAction'].push gitlab_view_link unless @gitlab_url.nil?
+ text['potentialAction'].push gitlab_issue_link unless @gitlab_url.nil?
+ text['potentialAction'].push jira_issue_link unless @jira_url.nil?
+
+ text
+ end
+
+ def details
+ details = {
+ "title" => "Details",
+ "facts" => []
+ }
+
+ details['facts'].push message_request unless @request_items.nil?
+ details['facts'].push message_backtrace unless @backtrace.nil?
+
+ details
+ end
+
+ def message_request
+ {
+ "name" => "Request",
+ "value" => "#{hash_presentation(@request_items)}\n "
+ }
+ end
+
+ def message_backtrace(size = 3)
+ text = []
+ size = @backtrace.size < size ? @backtrace.size : size
+ text << "```"
+ size.times { |i| text << "* " + @backtrace[i] }
+ text << "```"
+
+ {
+ "name" => "Backtrace",
+ "value" => "#{text.join(" \n")}"
+ }
+ end
+
+ def gitlab_view_link
+ {
+ "@type" => "ViewAction",
+ "name" => "🦊 View in GitLab",
+ "target" => [
+ "#{@gitlab_url}/#{@application_name}"
+ ]
+ }
+ end
+
+ def gitlab_issue_link
+ link = [@gitlab_url, @application_name, "issues", "new"].join("/")
+ params = {
+ "issue[title]" => ["[BUG] Error 500 :",
+ controller_and_method,
+ "(#{@exception.class})",
+ @exception.message].compact.join(" ")
+ }.to_query
+
+ {
+ "@type" => "ViewAction",
+ "name" => "🦊 Create Issue in GitLab",
+ "target" => [
+ "#{link}/?#{params}"
+ ]
+ }
+ end
+
+ def jira_issue_link
+ {
+ "@type" => "ViewAction",
+ "name" => "🐞 Create Issue in Jira",
+ "target" => [
+ "#{@jira_url}/secure/CreateIssue!default.jspa"
+ ]
+ }
+ 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")
+ end
+ end
+end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/lib/exception_notifier/views/exception_notifier/background_exception_notification.text.erb
new/lib/exception_notifier/views/exception_notifier/background_exception_notification.text.erb
---
old/lib/exception_notifier/views/exception_notifier/background_exception_notification.text.erb
2017-08-12 22:52:29.000000000 +0200
+++
new/lib/exception_notifier/views/exception_notifier/background_exception_notification.text.erb
2018-11-22 23:02:26.000000000 +0100
@@ -3,12 +3,12 @@
<%= @exception.message %>
<%= @backtrace.first %>
- <% sections = @sections.map do |section|
- summary = render(section).strip
- unless summary.blank?
- title = render("title", :title => section).strip
- "#{title}\n\n#{summary.gsub(/^/, " ")}\n\n"
- end
- end.join
- %>
- <%= raw sections %>
+<% sections = @sections.map do |section|
+ summary = render(section).strip
+ unless summary.blank?
+ title = render("title", :title => section).strip
+ "#{title}\n\n#{summary.gsub(/^/, " ")}\n\n"
+ end
+ end.join
+%>
+<%= raw sections %>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/lib/exception_notifier.rb
new/lib/exception_notifier.rb
--- old/lib/exception_notifier.rb 2017-08-12 22:52:29.000000000 +0200
+++ new/lib/exception_notifier.rb 2018-11-22 23:02:26.000000000 +0100
@@ -17,6 +17,9 @@
autoload :IrcNotifier, 'exception_notifier/irc_notifier'
autoload :SlackNotifier, 'exception_notifier/slack_notifier'
autoload :MattermostNotifier, 'exception_notifier/mattermost_notifier'
+ autoload :TeamsNotifier, 'exception_notifier/teams_notifier'
+ autoload :SnsNotifier, 'exception_notifier/sns_notifier'
+ autoload :GoogleChatNotifier, 'exception_notifier/google_chat_notifier'
class UndefinedNotifierError < StandardError; end
@@ -42,7 +45,7 @@
self.testing_mode = true
end
- def notify_exception(exception, options={})
+ def notify_exception(exception, options={}, &block)
return false if ignored_exception?(options[:ignore_exceptions],
exception)
return false if ignored?(exception, options)
if error_grouping
@@ -52,7 +55,7 @@
selected_notifiers = options.delete(:notifiers) || notifiers
[*selected_notifiers].each do |notifier|
- fire_notification(notifier, exception, options.dup)
+ fire_notification(notifier, exception, options.dup, &block)
end
true
end
@@ -104,12 +107,14 @@
end
def ignored_exception?(ignore_array, exception)
- (Array(ignored_exceptions) +
Array(ignore_array)).map(&:to_s).include?(exception.class.name)
+ all_ignored_exceptions = (Array(ignored_exceptions) +
Array(ignore_array)).map(&:to_s)
+ exception_ancestors = exception.class.ancestors.map(&:to_s)
+ !(all_ignored_exceptions & exception_ancestors).empty?
end
- def fire_notification(notifier_name, exception, options)
+ def fire_notification(notifier_name, exception, options, &block)
notifier = registered_exception_notifier(notifier_name)
- notifier.call(exception, options)
+ notifier.call(exception, options, &block)
rescue Exception => e
raise e if @@testing_mode
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/metadata new/metadata
--- old/metadata 2017-08-12 22:52:29.000000000 +0200
+++ new/metadata 2018-11-22 23:02:26.000000000 +0100
@@ -1,7 +1,7 @@
--- !ruby/object:Gem::Specification
name: exception_notification
version: !ruby/object:Gem::Version
- version: 4.2.2
+ version: 4.3.0
platform: ruby
authors:
- Jamis Buck
@@ -9,7 +9,7 @@
autorequire:
bindir: bin
cert_chain: []
-date: 2017-08-12 00:00:00.000000000 Z
+date: 2018-11-22 00:00:00.000000000 Z
dependencies:
- !ruby/object:Gem::Dependency
name: actionmailer
@@ -231,6 +231,20 @@
- - ">="
- !ruby/object:Gem::Version
version: 1.0.0
+- !ruby/object:Gem::Dependency
+ name: aws-sdk-sns
+ requirement: !ruby/object:Gem::Requirement
+ requirements:
+ - - "~>"
+ - !ruby/object:Gem::Version
+ version: '1'
+ type: :development
+ prerelease: false
+ version_requirements: !ruby/object:Gem::Requirement
+ requirements:
+ - - "~>"
+ - !ruby/object:Gem::Version
+ version: '1'
description:
email: [email protected]
executables: []
@@ -256,6 +270,7 @@
- gemfiles/rails4_1.gemfile
- gemfiles/rails4_2.gemfile
- gemfiles/rails5_0.gemfile
+- gemfiles/rails5_1.gemfile
- lib/exception_notification.rb
- lib/exception_notification/rack.rb
- lib/exception_notification/rails.rb
@@ -265,6 +280,7 @@
- lib/exception_notifier/base_notifier.rb
- lib/exception_notifier/campfire_notifier.rb
- lib/exception_notifier/email_notifier.rb
+- lib/exception_notifier/google_chat_notifier.rb
- lib/exception_notifier/hipchat_notifier.rb
- lib/exception_notifier/irc_notifier.rb
- lib/exception_notifier/mattermost_notifier.rb
@@ -272,6 +288,8 @@
- lib/exception_notifier/modules/error_grouping.rb
- lib/exception_notifier/notifier.rb
- lib/exception_notifier/slack_notifier.rb
+- lib/exception_notifier/sns_notifier.rb
+- lib/exception_notifier/teams_notifier.rb
- lib/exception_notifier/views/exception_notifier/_backtrace.html.erb
- lib/exception_notifier/views/exception_notifier/_backtrace.text.erb
- lib/exception_notifier/views/exception_notifier/_data.html.erb
@@ -346,12 +364,15 @@
- test/exception_notification/rack_test.rb
- test/exception_notifier/campfire_notifier_test.rb
- test/exception_notifier/email_notifier_test.rb
+- test/exception_notifier/google_chat_notifier_test.rb
- test/exception_notifier/hipchat_notifier_test.rb
- test/exception_notifier/irc_notifier_test.rb
- test/exception_notifier/mattermost_notifier_test.rb
- test/exception_notifier/modules/error_grouping_test.rb
- test/exception_notifier/sidekiq_test.rb
- test/exception_notifier/slack_notifier_test.rb
+- test/exception_notifier/sns_notifier_test.rb
+- test/exception_notifier/teams_notifier_test.rb
- test/exception_notifier/webhook_notifier_test.rb
- test/exception_notifier_test.rb
- test/test_helper.rb
@@ -375,7 +396,7 @@
version: 1.8.11
requirements: []
rubyforge_project:
-rubygems_version: 2.5.1
+rubygems_version: 2.5.2
signing_key:
specification_version: 4
summary: Exception notification for Rails apps
@@ -435,12 +456,15 @@
- test/exception_notification/rack_test.rb
- test/exception_notifier/campfire_notifier_test.rb
- test/exception_notifier/email_notifier_test.rb
+- test/exception_notifier/google_chat_notifier_test.rb
- test/exception_notifier/hipchat_notifier_test.rb
- test/exception_notifier/irc_notifier_test.rb
- test/exception_notifier/mattermost_notifier_test.rb
- test/exception_notifier/modules/error_grouping_test.rb
- test/exception_notifier/sidekiq_test.rb
- test/exception_notifier/slack_notifier_test.rb
+- test/exception_notifier/sns_notifier_test.rb
+- test/exception_notifier/teams_notifier_test.rb
- test/exception_notifier/webhook_notifier_test.rb
- test/exception_notifier_test.rb
- test/test_helper.rb
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/test/exception_notifier/google_chat_notifier_test.rb
new/test/exception_notifier/google_chat_notifier_test.rb
--- old/test/exception_notifier/google_chat_notifier_test.rb 1970-01-01
01:00:00.000000000 +0100
+++ new/test/exception_notifier/google_chat_notifier_test.rb 2018-11-22
23:02:26.000000000 +0100
@@ -0,0 +1,128 @@
+require 'test_helper'
+require 'httparty'
+
+class GoogleChatNotifierTest < ActiveSupport::TestCase
+
+ test "should send notification if properly configured" do
+ options = {
+ :webhook_url => 'http://localhost:8000'
+ }
+ google_chat_notifier = ExceptionNotifier::GoogleChatNotifier.new
+ google_chat_notifier.httparty = FakeHTTParty.new
+
+ options = google_chat_notifier.call ArgumentError.new("foo"), options
+
+ body = ActiveSupport::JSON.decode options[:body]
+ assert body.has_key? 'text'
+
+ text = body['text'].split("\n")
+ assert_equal 6, text.size
+ assert_equal 'Application: *dummy*', text[1]
+ assert_equal 'An *ArgumentError* occured.', text[2]
+ assert_equal '*foo*', text[5]
+ end
+
+ test "should use 'An' for exceptions count if :accumulated_errors_count
option is nil" do
+ google_chat_notifier = ExceptionNotifier::GoogleChatNotifier.new
+ exception = ArgumentError.new("foo")
+ google_chat_notifier.instance_variable_set(:@exception, exception)
+ google_chat_notifier.instance_variable_set(:@options, {})
+
+ assert_includes google_chat_notifier.send(:header), "An *ArgumentError*
occured."
+ end
+
+ test "shoud use direct errors count if :accumulated_errors_count option is
5" do
+ google_chat_notifier = ExceptionNotifier::GoogleChatNotifier.new
+ exception = ArgumentError.new("foo")
+ google_chat_notifier.instance_variable_set(:@exception, exception)
+ google_chat_notifier.instance_variable_set(:@options, {
accumulated_errors_count: 5 })
+
+ assert_includes google_chat_notifier.send(:header), "5 *ArgumentError*
occured."
+ end
+
+ test "Message request should be formatted as hash" do
+ google_chat_notifier = ExceptionNotifier::GoogleChatNotifier.new
+ request_items = { url: 'http://test.address',
+ http_method: :get,
+ ip_address: '127.0.0.1',
+ parameters: '{"id"=>"foo"}',
+ timestamp: Time.parse('2018-08-13 12:13:24 UTC') }
+ google_chat_notifier.instance_variable_set(:@request_items, request_items)
+
+ message_request = google_chat_notifier.send(:message_request).join("\n")
+ assert_includes message_request, '* url : http://test.address'
+ assert_includes message_request, '* http_method : get'
+ assert_includes message_request, '* ip_address : 127.0.0.1'
+ assert_includes message_request, '* parameters : {"id"=>"foo"}'
+ assert_includes message_request, '* timestamp : 2018-08-13 12:13:24 UTC'
+ end
+
+ test 'backtrace with less than 3 lines should be displayed fully' do
+ google_chat_notifier = ExceptionNotifier::GoogleChatNotifier.new
+
+ backtrace = ["app/controllers/my_controller.rb:53:in
`my_controller_params'", "app/controllers/my_controller.rb:34:in `update'"]
+ google_chat_notifier.instance_variable_set(:@backtrace, backtrace)
+
+ message_backtrace =
google_chat_notifier.send(:message_backtrace).join("\n")
+ assert_includes message_backtrace, "*
app/controllers/my_controller.rb:53:in `my_controller_params'"
+ assert_includes message_backtrace, "*
app/controllers/my_controller.rb:34:in `update'"
+ end
+
+ test 'backtrace with more than 3 lines should display only top 3 lines' do
+ google_chat_notifier = ExceptionNotifier::GoogleChatNotifier.new
+
+ backtrace = ["app/controllers/my_controller.rb:99:in `specific_function'",
"app/controllers/my_controller.rb:70:in `specific_param'",
"app/controllers/my_controller.rb:53:in `my_controller_params'",
"app/controllers/my_controller.rb:34:in `update'"]
+ google_chat_notifier.instance_variable_set(:@backtrace, backtrace)
+
+ message_backtrace =
google_chat_notifier.send(:message_backtrace).join("\n")
+ assert_includes message_backtrace, "*
app/controllers/my_controller.rb:99:in `specific_function'"
+ assert_includes message_backtrace, "*
app/controllers/my_controller.rb:70:in `specific_param'"
+ assert_includes message_backtrace, "*
app/controllers/my_controller.rb:53:in `my_controller_params'"
+ assert_not_includes message_backtrace, "*
app/controllers/my_controller.rb:34:in `update'"
+ end
+
+ test 'Get text with backtrace and request info' do
+ google_chat_notifier = ExceptionNotifier::GoogleChatNotifier.new
+
+ backtrace = ["app/controllers/my_controller.rb:53:in
`my_controller_params'", "app/controllers/my_controller.rb:34:in `update'"]
+ google_chat_notifier.instance_variable_set(:@backtrace, backtrace)
+
+ request_items = { url: 'http://test.address',
+ http_method: :get,
+ ip_address: '127.0.0.1',
+ parameters: '{"id"=>"foo"}',
+ timestamp: Time.parse('2018-08-13 12:13:24 UTC') }
+ google_chat_notifier.instance_variable_set(:@request_items, request_items)
+
+ google_chat_notifier.instance_variable_set(:@options,
{accumulated_errors_count: 0})
+
+ google_chat_notifier.instance_variable_set(:@application_name, 'dummy')
+
+ exception = ArgumentError.new("foo")
+ google_chat_notifier.instance_variable_set(:@exception, exception)
+
+ text = google_chat_notifier.send(:exception_text)
+ expected_text = %q(
+Application: *dummy*
+An *ArgumentError* occured.
+
+⚠️ Error 500 in test ⚠️
+*foo*
+
+*Request:*
+```
+* url : http://test.address
+* http_method : get
+* ip_address : 127.0.0.1
+* parameters : {"id"=>"foo"}
+* timestamp : 2018-08-13 12:13:24 UTC
+```
+
+*Backtrace:*
+```
+* app/controllers/my_controller.rb:53:in `my_controller_params'
+* app/controllers/my_controller.rb:34:in `update'
+```)
+ assert_equal text, expected_text
+ end
+end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/test/exception_notifier/modules/error_grouping_test.rb
new/test/exception_notifier/modules/error_grouping_test.rb
--- old/test/exception_notifier/modules/error_grouping_test.rb 2017-08-12
22:52:29.000000000 +0200
+++ new/test/exception_notifier/modules/error_grouping_test.rb 2018-11-22
23:02:26.000000000 +0100
@@ -5,7 +5,7 @@
setup do
module TestModule
include ExceptionNotifier::ErrorGrouping
- @@error_grouping_cache =
ActiveSupport::Cache::FileStore.new("test/dummy/tmp/cache")
+ @@error_grouping_cache =
ActiveSupport::Cache::FileStore.new("test/dummy/tmp/non_default_location")
end
@exception = RuntimeError.new("ERROR")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/test/exception_notifier/sns_notifier_test.rb
new/test/exception_notifier/sns_notifier_test.rb
--- old/test/exception_notifier/sns_notifier_test.rb 1970-01-01
01:00:00.000000000 +0100
+++ new/test/exception_notifier/sns_notifier_test.rb 2018-11-22
23:02:26.000000000 +0100
@@ -0,0 +1,126 @@
+require 'test_helper'
+require 'aws-sdk-sns'
+
+class SnsNotifierTest < ActiveSupport::TestCase
+ def setup
+ @exception = fake_exception
+ @exception.stubs(:class).returns('MyException')
+ @exception.stubs(:backtrace).returns(fake_backtrace)
+ @exception.stubs(:message).returns("undefined method 'method=' for Empty")
+ @options = {
+ access_key_id: 'my-access_key_id',
+ secret_access_key: 'my-secret_access_key',
+ region: 'us-east',
+ topic_arn: 'topicARN',
+ sns_prefix: '[App Exception]',
+ }
+ Socket.stubs(:gethostname).returns('example.com')
+ end
+
+ # initialize
+
+ test 'should initialize aws notifier with received params' do
+ Aws::SNS::Client.expects(:new).with(
+ region: 'us-east',
+ access_key_id: 'my-access_key_id',
+ secret_access_key: 'my-secret_access_key'
+ )
+
+ ExceptionNotifier::SnsNotifier.new(@options)
+ end
+
+ test 'should raise an exception if region is not received' do
+ @options[:region] = nil
+
+ error = assert_raises ArgumentError do
+ ExceptionNotifier::SnsNotifier.new(@options)
+ end
+ assert_equal "You must provide 'region' option", error.message
+ end
+
+ test 'should raise an exception on publish if access_key_id is not received'
do
+ @options[:access_key_id] = nil
+ error = assert_raises ArgumentError do
+ ExceptionNotifier::SnsNotifier.new(@options)
+ end
+
+ assert_equal "You must provide 'access_key_id' option", error.message
+ end
+
+ test 'should raise an exception on publish if secret_access_key is not
received' do
+ @options[:secret_access_key] = nil
+ error = assert_raises ArgumentError do
+ ExceptionNotifier::SnsNotifier.new(@options)
+ end
+
+ assert_equal "You must provide 'secret_access_key' option", error.message
+ end
+
+ # call
+
+ test 'should send a sns notification in background' do
+ Aws::SNS::Client.any_instance.expects(:publish).with(
+ {
+ topic_arn: "topicARN",
+ message: "3 MyException occured in background\n"\
+ "Exception: undefined method 'method=' for Empty\n"\
+ "Hostname: example.com\n"\
+ "Backtrace:\n#{fake_backtrace.join("\n")}\n",
+ subject: "[App Exception] - 3 MyException occurred"
+ })
+
+ sns_notifier = ExceptionNotifier::SnsNotifier.new(@options)
+ sns_notifier.call(@exception, { accumulated_errors_count: 3 })
+ end
+
+ test 'should send a sns notification with controller#action information' do
+ ExamplesController.any_instance.stubs(:action_name).returns('index')
+
+ Aws::SNS::Client.any_instance.expects(:publish).with(
+ {
+ topic_arn: "topicARN",
+ message: "A MyException occurred while GET </examples> "\
+ "was processed by examples#index\n"\
+ "Exception: undefined method 'method=' for Empty\n"\
+ "Hostname: example.com\n"\
+ "Backtrace:\n#{fake_backtrace.join("\n")}\n",
+ subject: "[App Exception] - A MyException occurred"
+ })
+
+ sns_notifier = ExceptionNotifier::SnsNotifier.new(@options)
+ sns_notifier.call(@exception,
+ env: {
+ 'REQUEST_METHOD' => 'GET',
+ 'REQUEST_URI' => '/examples',
+ 'action_controller.instance' => ExamplesController.new
+ }
+ )
+ end
+
+ private
+
+ class ExamplesController < ActionController::Base; end
+
+ def fake_exception
+ begin
+ 1 / 0
+ rescue Exception => e
+ e
+ end
+ end
+
+ def fake_exception_without_backtrace
+ StandardError.new('my custom error')
+ end
+
+ def fake_backtrace
+ [
+ 'backtrace line 1',
+ 'backtrace line 2',
+ 'backtrace line 3',
+ 'backtrace line 4',
+ 'backtrace line 5',
+ 'backtrace line 6'
+ ]
+ end
+end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/test/exception_notifier/teams_notifier_test.rb
new/test/exception_notifier/teams_notifier_test.rb
--- old/test/exception_notifier/teams_notifier_test.rb 1970-01-01
01:00:00.000000000 +0100
+++ new/test/exception_notifier/teams_notifier_test.rb 2018-11-22
23:02:26.000000000 +0100
@@ -0,0 +1,93 @@
+require 'test_helper'
+require 'httparty'
+
+class TeamsNotifierTest < ActiveSupport::TestCase
+
+ test "should send notification if properly configured" do
+ options = {
+ :webhook_url => 'http://localhost:8000'
+ }
+ teams_notifier = ExceptionNotifier::TeamsNotifier.new
+ teams_notifier.httparty = FakeHTTParty.new
+
+ options = teams_notifier.call ArgumentError.new("foo"), options
+
+ body = ActiveSupport::JSON.decode options[:body]
+ assert body.has_key? 'title'
+ assert body.has_key? 'sections'
+
+ sections = body['sections']
+ header = sections[0]
+
+ assert_equal 2, sections.size
+ assert_equal 'A *ArgumentError* occurred.', header['activityTitle']
+ assert_equal 'foo', header['activitySubtitle']
+ end
+
+ test "should send notification with create gitlab issue link if specified" do
+ options = {
+ :webhook_url => 'http://localhost:8000',
+ :git_url => 'github.com/aschen'
+ }
+ teams_notifier = ExceptionNotifier::TeamsNotifier.new
+ teams_notifier.httparty = FakeHTTParty.new
+
+ options = teams_notifier.call ArgumentError.new("foo"), options
+
+ body = ActiveSupport::JSON.decode options[:body]
+
+ potential_action = body['potentialAction']
+ assert_equal 2, potential_action.size
+ assert_equal '🦊 View in GitLab', potential_action[0]['name']
+ assert_equal '🦊 Create Issue in GitLab', potential_action[1]['name']
+ end
+
+ test 'should add other HTTParty options to params' do
+ options = {
+ :webhook_url => 'http://localhost:8000',
+ :username => "Test Bot",
+ :avatar => 'http://site.com/icon.png',
+ :basic_auth => {
+ :username => 'clara',
+ :password => 'password'
+ }
+ }
+ teams_notifier = ExceptionNotifier::TeamsNotifier.new
+ teams_notifier.httparty = FakeHTTParty.new
+
+ options = teams_notifier.call ArgumentError.new("foo"), options
+
+ assert options.has_key? :basic_auth
+ assert 'clara', options[:basic_auth][:username]
+ assert 'password', options[:basic_auth][:password]
+ end
+
+ test "should use 'A' for exceptions count if :accumulated_errors_count
option is nil" do
+ teams_notifier = ExceptionNotifier::TeamsNotifier.new
+ exception = ArgumentError.new("foo")
+ teams_notifier.instance_variable_set(:@exception, exception)
+ teams_notifier.instance_variable_set(:@options, {})
+
+ message_text = teams_notifier.send(:message_text)
+ header = message_text['sections'][0]
+ assert_equal 'A *ArgumentError* occurred.', header['activityTitle']
+ end
+
+ test "should use direct errors count if :accumulated_errors_count option is
5" do
+ teams_notifier = ExceptionNotifier::TeamsNotifier.new
+ exception = ArgumentError.new("foo")
+ teams_notifier.instance_variable_set(:@exception, exception)
+ teams_notifier.instance_variable_set(:@options, {
accumulated_errors_count: 5 })
+ message_text = teams_notifier.send(:message_text)
+ header = message_text['sections'][0]
+ assert_equal '5 *ArgumentError* occurred.', header['activityTitle']
+ end
+end
+
+class FakeHTTParty
+
+ def post(url, options)
+ return options
+ end
+
+end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/test/exception_notifier_test.rb
new/test/exception_notifier_test.rb
--- old/test/exception_notifier_test.rb 2017-08-12 22:52:30.000000000 +0200
+++ new/test/exception_notifier_test.rb 2018-11-22 23:02:26.000000000 +0100
@@ -110,6 +110,35 @@
assert_equal @notifier_calls, 1
end
+ test "should not send notification if subclass of one of ignored exceptions"
do
+ ExceptionNotifier.register_exception_notifier(:test, @test_notifier)
+
+ class StandardErrorSubclass < StandardError
+ end
+
+ exception = StandardErrorSubclass.new
+
+ ExceptionNotifier.notify_exception(exception, {:notifiers => :test})
+ assert_equal @notifier_calls, 1
+
+ ExceptionNotifier.notify_exception(exception, {:notifiers => :test,
:ignore_exceptions => 'StandardError' })
+ assert_equal @notifier_calls, 1
+ end
+
+ test "should call received block" do
+ @block_called = false
+ notifier = lambda { |exception, options, &block| block.call }
+ ExceptionNotifier.register_exception_notifier(:test, notifier)
+
+ exception = ExceptionOne.new
+
+ ExceptionNotifier.notify_exception(exception) do
+ @block_called = true
+ end
+
+ assert @block_called
+ end
+
test "should not call group_error! or send_notification? if error_grouping
false" do
exception = StandardError.new
ExceptionNotifier.expects(:group_error!).never