rusen 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +23 -0
- data/LICENSE +22 -0
- data/README.md +262 -0
- data/Rakefile +65 -0
- data/lib/rusen.rb +6 -2
- data/lib/rusen/middleware/rusen_rack.rb +13 -9
- data/lib/rusen/middleware/rusen_sidekiq.rb +19 -0
- data/lib/rusen/notification.rb +14 -6
- data/lib/rusen/notifier.rb +15 -7
- data/lib/rusen/notifiers.rb +29 -0
- data/lib/rusen/notifiers/base_notifier.rb +53 -0
- data/lib/rusen/notifiers/io_notifier.rb +17 -42
- data/lib/rusen/notifiers/log4r_notifier.rb +70 -0
- data/lib/rusen/notifiers/mail_notifier.rb +86 -0
- data/lib/rusen/notifiers/{email_notifier.rb → pony_notifier.rb} +22 -19
- data/lib/rusen/settings.rb +35 -2
- data/lib/rusen/sidekiq.rb +19 -0
- data/lib/rusen/templates/email_template.html.erb +28 -74
- data/lib/rusen/templates/io_template.txt.erb +19 -0
- data/lib/rusen/templates/log4r_template.txt.erb +19 -0
- data/lib/rusen/utils/parameter_filter.rb +68 -0
- data/lib/rusen/version.rb +3 -0
- metadata +157 -32
data/lib/rusen/notification.rb
CHANGED
@@ -5,13 +5,21 @@ module Rusen
|
|
5
5
|
|
6
6
|
attr_reader :exception, :request, :environment, :session
|
7
7
|
|
8
|
-
def initialize(exception, request =
|
9
|
-
@exception
|
10
|
-
@request
|
11
|
-
@environment = environment
|
12
|
-
@session
|
8
|
+
def initialize(exception, request = {} , environment = {}, session = {})
|
9
|
+
@exception = exception
|
10
|
+
@request = request
|
11
|
+
@environment = environment
|
12
|
+
@session = session
|
13
|
+
end
|
14
|
+
|
15
|
+
def session
|
16
|
+
if @session.respond_to?(:each)
|
17
|
+
@session
|
18
|
+
else
|
19
|
+
@session.to_hash
|
20
|
+
end
|
13
21
|
end
|
14
22
|
|
15
23
|
end
|
16
24
|
|
17
|
-
end
|
25
|
+
end
|
data/lib/rusen/notifier.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
|
+
require 'rusen/notifiers'
|
1
2
|
require 'rusen/notification'
|
2
|
-
require 'rusen/notifiers/io_notifier'
|
3
|
-
require 'rusen/notifiers/email_notifier'
|
4
3
|
|
5
4
|
module Rusen
|
6
5
|
|
@@ -10,11 +9,20 @@ module Rusen
|
|
10
9
|
@settings = settings
|
11
10
|
|
12
11
|
@notifiers = []
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
12
|
+
@settings.outputs.each do |ident|
|
13
|
+
ident = Notifiers.check_deprecation(ident)
|
14
|
+
# For notifiers bundled in this gem
|
15
|
+
klass = Notifiers.load_klass(ident)
|
16
|
+
if klass.nil?
|
17
|
+
Notifiers.constants.each do |constant|
|
18
|
+
klass = Notifiers.const_get(constant)
|
19
|
+
next unless klass.is_a?(Class)
|
20
|
+
break if ident == klass.identification_symbol
|
21
|
+
klass = nil
|
22
|
+
end
|
17
23
|
end
|
24
|
+
raise "Unable to load Output Notifier identified by: #{ident}" if klass.nil? || !klass.is_a?(Class)
|
25
|
+
register(klass)
|
18
26
|
end
|
19
27
|
end
|
20
28
|
|
@@ -28,7 +36,7 @@ module Rusen
|
|
28
36
|
# @param [Hash<Object, Object>] request The request params
|
29
37
|
# @param [Hash<Object, Object>] environment The environment status.
|
30
38
|
# @param [Hash<Object, Object>] session The session status.
|
31
|
-
def notify(exception, request =
|
39
|
+
def notify(exception, request = {}, environment = {}, session = {})
|
32
40
|
begin
|
33
41
|
notification = Notification.new(exception, request, environment, session)
|
34
42
|
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Rusen
|
2
|
+
module Notifiers
|
3
|
+
|
4
|
+
NOTIFIERS = {
|
5
|
+
:pony => :PonyNotifier,
|
6
|
+
:mail => :MailNotifier,
|
7
|
+
:io => :IONotifier,
|
8
|
+
:log4r => :Log4rNotifier,
|
9
|
+
}
|
10
|
+
|
11
|
+
def self.load_klass(ident, klass_sym = nil)
|
12
|
+
klass_sym ||= NOTIFIERS[ident]
|
13
|
+
if klass_sym
|
14
|
+
require "rusen/notifiers/#{ident}_notifier" unless Notifiers.constants.include?(klass_sym)
|
15
|
+
Notifiers.const_get(klass_sym)
|
16
|
+
else
|
17
|
+
return nil
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.check_deprecation(ident)
|
22
|
+
if ident == :email
|
23
|
+
warn ':email is a deprecated output type. :pony replaces :email. A new alternative is :mail (mail gem).'
|
24
|
+
return :pony
|
25
|
+
end
|
26
|
+
return ident
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require_relative '../utils/parameter_filter'
|
3
|
+
|
4
|
+
module Rusen
|
5
|
+
module Notifiers
|
6
|
+
|
7
|
+
class BaseNotifier
|
8
|
+
|
9
|
+
def self.identification_symbol
|
10
|
+
:base_notifier
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(settings)
|
14
|
+
@settings = settings.dup
|
15
|
+
end
|
16
|
+
|
17
|
+
def get_sessions(notification)
|
18
|
+
result = {}
|
19
|
+
|
20
|
+
include_session(result, notification.exception.backtrace, :backtrace)
|
21
|
+
include_session(result, notification.request, :request)
|
22
|
+
include_session(result, notification.session, :session)
|
23
|
+
include_session(result, notification.environment, :environment)
|
24
|
+
|
25
|
+
result
|
26
|
+
end
|
27
|
+
|
28
|
+
def handle_notification_exception(exception)
|
29
|
+
name = self.class.identification_symbol.to_s
|
30
|
+
|
31
|
+
warn("Rusen: #{exception.message} prevented the #{name} notifier from login the error.")
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def include_session(sessions, session, session_key)
|
37
|
+
@settings.sections
|
38
|
+
|
39
|
+
if @settings.sections.include?(session_key) && session
|
40
|
+
session = parameter_filter.filter(session) if session_key != :backtrace
|
41
|
+
|
42
|
+
sessions[session_key.to_s.capitalize] = session
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def parameter_filter
|
47
|
+
@parameter_filter ||= ParameterFilter.new(@settings.filter_parameters)
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
@@ -1,7 +1,9 @@
|
|
1
|
+
require_relative 'base_notifier'
|
2
|
+
|
1
3
|
module Rusen
|
2
4
|
module Notifiers
|
3
5
|
|
4
|
-
class IONotifier
|
6
|
+
class IONotifier < BaseNotifier
|
5
7
|
|
6
8
|
STDOUT = $stdout
|
7
9
|
|
@@ -10,58 +12,31 @@ module Rusen
|
|
10
12
|
end
|
11
13
|
|
12
14
|
def initialize(settings, output = STDOUT)
|
13
|
-
|
14
|
-
@output
|
15
|
+
super(settings)
|
16
|
+
@output = output
|
15
17
|
end
|
16
18
|
|
17
19
|
def notify(notification)
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
print_title('Backtrace')
|
22
|
-
|
23
|
-
@output.puts notification.exception.message
|
24
|
-
@output.puts notification.exception.backtrace
|
25
|
-
end
|
26
|
-
|
27
|
-
if @settings.sections.include?(:request)
|
28
|
-
print_title('Request')
|
29
|
-
|
30
|
-
print_hash(notification.request)
|
31
|
-
end
|
32
|
-
|
33
|
-
if @settings.sections.include?(:session)
|
34
|
-
print_title('Session')
|
35
|
-
|
36
|
-
print_hash(notification.session)
|
37
|
-
end
|
38
|
-
|
39
|
-
if @settings.sections.include?(:environment)
|
40
|
-
print_title('Environment')
|
41
|
-
|
42
|
-
print_hash(notification.environment)
|
43
|
-
end
|
20
|
+
@notification = notification
|
21
|
+
@sessions = get_sessions(@notification)
|
44
22
|
|
45
23
|
# We need to ignore all the exceptions thrown by IONotifier#notify.
|
46
|
-
|
47
|
-
|
48
|
-
|
24
|
+
@output.puts build_content
|
25
|
+
rescue Exception => exception
|
26
|
+
handle_notification_exception(exception)
|
49
27
|
end
|
50
28
|
|
51
29
|
private
|
52
30
|
|
53
|
-
def
|
54
|
-
|
55
|
-
@output.puts "#{title}:"
|
56
|
-
@output.puts '-------------------------------'
|
57
|
-
end
|
31
|
+
def build_content
|
32
|
+
template_path = File.expand_path('../../templates/io_template.txt.erb', __FILE__)
|
58
33
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
end
|
34
|
+
template = File.open(template_path).read
|
35
|
+
rhtml = ERB.new(template, nil, '-')
|
36
|
+
rhtml.result(binding)
|
63
37
|
end
|
38
|
+
|
64
39
|
end
|
65
40
|
|
66
41
|
end
|
67
|
-
end
|
42
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require_relative 'base_notifier'
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'log4r'
|
5
|
+
require 'log4r/yamlconfigurator'
|
6
|
+
rescue LoadError
|
7
|
+
puts <<-MESSAGE
|
8
|
+
[Rusen Error] To use log4r notifier add this to your Gemfile:
|
9
|
+
gem 'log4r'
|
10
|
+
MESSAGE
|
11
|
+
raise
|
12
|
+
end
|
13
|
+
|
14
|
+
module Rusen
|
15
|
+
module Notifiers
|
16
|
+
|
17
|
+
class Log4rNotifier < BaseNotifier
|
18
|
+
|
19
|
+
def self.identification_symbol
|
20
|
+
:log4r
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize(settings)
|
24
|
+
super(settings)
|
25
|
+
|
26
|
+
load_config(@settings.log4r_config_file)
|
27
|
+
|
28
|
+
@logger = logger_instance(@settings.logger_name)
|
29
|
+
end
|
30
|
+
|
31
|
+
def notify(notification)
|
32
|
+
@notification = notification
|
33
|
+
@sessions = get_sessions(@notification)
|
34
|
+
|
35
|
+
# We need to ignore all the exceptions thrown by Log4rNotifier#notify.
|
36
|
+
@logger.error { build_content }
|
37
|
+
rescue Exception => exception
|
38
|
+
handle_notification_exception(exception)
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def build_content
|
44
|
+
template_path = File.expand_path('../../templates/log4r_template.txt.erb', __FILE__)
|
45
|
+
|
46
|
+
template = File.open(template_path).read
|
47
|
+
rhtml = ERB.new(template, nil, '-')
|
48
|
+
rhtml.result(binding)
|
49
|
+
end
|
50
|
+
|
51
|
+
def logger_instance(name = nil)
|
52
|
+
if name
|
53
|
+
Log4r::Logger[name]
|
54
|
+
else
|
55
|
+
Log4r::Logger.root
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Loads the given config file.
|
60
|
+
#
|
61
|
+
# @param [String] config_yml Configuration file path.
|
62
|
+
def load_config(config_yml)
|
63
|
+
if config_yml
|
64
|
+
Log4r::YamlConfigurator.load_yaml_file(config_yml)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require_relative 'base_notifier'
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'mail'
|
5
|
+
rescue LoadError
|
6
|
+
puts <<-MESSAGE
|
7
|
+
[Rusen Error] To use Mail notifier add this to your Gemfile:
|
8
|
+
gem 'mail'
|
9
|
+
MESSAGE
|
10
|
+
raise
|
11
|
+
end
|
12
|
+
|
13
|
+
module Rusen
|
14
|
+
module Notifiers
|
15
|
+
|
16
|
+
class MailNotifier < BaseNotifier
|
17
|
+
|
18
|
+
def self.identification_symbol
|
19
|
+
:mail
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(settings)
|
23
|
+
super(settings)
|
24
|
+
|
25
|
+
if @settings && @settings.smtp_settings.any?
|
26
|
+
smtp_settings = @settings.smtp_settings
|
27
|
+
|
28
|
+
Mail.defaults do
|
29
|
+
delivery_method :smtp, smtp_settings
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def notify(notification)
|
35
|
+
@notification = notification
|
36
|
+
@sessions = get_sessions(@notification)
|
37
|
+
|
38
|
+
options = email_options.dup
|
39
|
+
options.merge!({:body => build_body})
|
40
|
+
mail = Mail.new do
|
41
|
+
from options[:from]
|
42
|
+
to options[:to]
|
43
|
+
reply_to options[:reply_to]
|
44
|
+
cc options[:cc]
|
45
|
+
bcc options[:bcc]
|
46
|
+
subject options[:subject]
|
47
|
+
html_part do
|
48
|
+
content_type "text/html; charset=#{options[:charset]}"
|
49
|
+
body options[:body]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# We need to ignore all the exceptions thrown by MailNotifier#notify.
|
54
|
+
mail.deliver!
|
55
|
+
rescue Exception => exception
|
56
|
+
handle_notification_exception(exception)
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def email_options
|
62
|
+
{
|
63
|
+
:to => @settings.exception_recipients,
|
64
|
+
:charset => 'UTF-8',
|
65
|
+
:from => @settings.sender_address,
|
66
|
+
:subject => email_subject
|
67
|
+
}
|
68
|
+
end
|
69
|
+
|
70
|
+
def email_subject
|
71
|
+
@settings.email_prefix + "#{@notification.exception.class}: #{@notification.exception.message}"
|
72
|
+
end
|
73
|
+
|
74
|
+
def build_body
|
75
|
+
template_path = File.expand_path('../../templates/email_template.html.erb', __FILE__)
|
76
|
+
|
77
|
+
template = File.open(template_path).read
|
78
|
+
rhtml = ERB.new(template, nil, '-')
|
79
|
+
rhtml.result(binding)
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
@@ -1,30 +1,32 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require_relative 'base_notifier'
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'pony'
|
5
|
+
rescue LoadError
|
6
|
+
puts <<-MESSAGE
|
7
|
+
[Rusen Error] To use Pony notifier add this to your Gemfile:
|
8
|
+
gem 'pony'
|
9
|
+
MESSAGE
|
10
|
+
raise
|
11
|
+
end
|
3
12
|
|
4
13
|
module Rusen
|
5
14
|
module Notifiers
|
6
15
|
|
7
|
-
class
|
16
|
+
class PonyNotifier < BaseNotifier
|
8
17
|
|
9
18
|
def self.identification_symbol
|
10
|
-
:
|
11
|
-
end
|
12
|
-
|
13
|
-
def initialize(settings)
|
14
|
-
@settings = settings
|
19
|
+
:pony
|
15
20
|
end
|
16
21
|
|
17
22
|
def notify(notification)
|
18
|
-
|
19
|
-
|
23
|
+
@notification = notification
|
24
|
+
@sessions = get_sessions(@notification)
|
20
25
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
warn("Rusen: #{e.class}: #{e.message} prevented the notification email from being sent.")
|
26
|
-
puts e.backtrace
|
27
|
-
end
|
26
|
+
# We need to ignore all the exceptions thrown by PonyNotifier#notify.
|
27
|
+
Pony.mail(email_options.merge({:body => build_body}))
|
28
|
+
rescue Exception => exception
|
29
|
+
handle_notification_exception(exception)
|
28
30
|
end
|
29
31
|
|
30
32
|
private
|
@@ -32,7 +34,7 @@ module Rusen
|
|
32
34
|
def email_options
|
33
35
|
{
|
34
36
|
:to => @settings.exception_recipients,
|
35
|
-
:via =>
|
37
|
+
:via => @settings.email_via,
|
36
38
|
:charset => 'utf-8',
|
37
39
|
:from => @settings.sender_address,
|
38
40
|
:headers => { 'Content-Type' => 'text/html' },
|
@@ -49,11 +51,12 @@ module Rusen
|
|
49
51
|
template_path = File.expand_path('../../templates/email_template.html.erb', __FILE__)
|
50
52
|
|
51
53
|
template = File.open(template_path).read
|
52
|
-
rhtml = ERB.new(template)
|
54
|
+
rhtml = ERB.new(template, nil, '-')
|
53
55
|
rhtml.result(binding)
|
54
56
|
end
|
55
57
|
|
56
58
|
end
|
57
59
|
|
58
60
|
end
|
61
|
+
|
59
62
|
end
|