exception_no 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ ZDg1YTk5NDNkNmRhNTA4NGVmNzE1ZTU3YzcwZDM3MGRlOWUyZWFiZg==
5
+ data.tar.gz: !binary |-
6
+ Yjc4Mzk0NjQzZWFjNjI4MWRjMDQ1OTA2Y2FiOGY3MWNjZjA2MjAyNA==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ YjQ1NGJmNjY1YWM2ZDc1OGJkNjMzYWQzZGZjNmJjNTE2YmNlZDBmMzdjYTgy
10
+ NDM1M2EzNmJkOWZiOTU0MzRkNWZlZDQyNTExZmU0NzY3MGJjMDgzYmJiYzMw
11
+ NTA0NDI5MjFmYWZiNjRjMDExZjZhMjRmMGZmNDkzZjA2MmYwZTI=
12
+ data.tar.gz: !binary |-
13
+ MjVhNzkxY2E2ZDFhY2UzNzUzMjJkMTIzNmY0MmZmY2NmNDdjOTU4ODVmOGRm
14
+ NDYwYjU1NTgyMmZlNWYwNGJhMmIwNTFlZDRiODk0M2FjMTVjOTQ1M2E1N2E0
15
+ ODU4ZGQxM2FmNTczNGE4NjI3NzY4MzRkM2M5Y2MzYTJlNTAzODg=
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ .gs
data/Makefile ADDED
@@ -0,0 +1,4 @@
1
+ test:
2
+ cutest test/*.rb
3
+
4
+ .PHONY: test
@@ -0,0 +1,16 @@
1
+ require File.expand_path("lib/exception_no", File.dirname(__FILE__))
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = "exception_no"
5
+ s.version = ExceptionNo::VERSION
6
+ s.summary = "Truly basic exception notification."
7
+ s.authors = ["Educabilia", "Damian Janowski"]
8
+ s.email = ["opensource@educabilia.com", "djanowski@dimaion.com"]
9
+ s.homepage = "https://github.com/djanowski/exception_no"
10
+
11
+ s.files = `git ls-files`.split("\n")
12
+ s.test_files = `git ls-files -- {test}/*`.split("\n")
13
+
14
+ s.add_development_dependency "mini-smtp-server"
15
+ s.add_development_dependency "cutest"
16
+ end
@@ -0,0 +1,81 @@
1
+ require "net/smtp"
2
+ require "erb"
3
+
4
+ class ExceptionNo
5
+ VERSION = "0.0.1"
6
+
7
+ attr_accessor :backtrace_filter
8
+
9
+ def initialize(config = {})
10
+ @config = config
11
+ @template = ERB.new(TEMPLATE)
12
+
13
+ @backtrace_filter = -> line { true }
14
+ end
15
+
16
+ def _notify(exception, options = {})
17
+ body = @template.result(binding)
18
+
19
+ Net::SMTP.start(@config.fetch(:host), @config.fetch(:port, 25)) do |smtp|
20
+ smtp.send_message(body, @config.fetch(:from), @config.fetch(:to))
21
+ end
22
+ end
23
+
24
+ def notify(exception, options = {})
25
+ begin
26
+ _notify(exception, options)
27
+ rescue => notification_error
28
+ $stderr.write("*** FAILED SENDING ERROR NOTIFICATION\n")
29
+ $stderr.write("*** #{notification_error.class}: #{notification_error}\n")
30
+ $stderr.write("*** #{exception.class}: #{exception.message}\n")
31
+
32
+ exception.backtrace.each do |line|
33
+ $stderr.write("*** #{line}\n")
34
+ end
35
+ end
36
+ end
37
+
38
+ TEMPLATE = (<<-'EMAIL').gsub(/^ {2}/, '')
39
+ From: <%= @config[:from_alias] %> <<%= @config[:from] %>>
40
+ To: <<%= @config[:to] %>>
41
+ Subject: <%= exception.class %>: <%= exception.message.split.join(" ") %>
42
+
43
+ <%= options[:body] %>
44
+
45
+ <%= "~" * 80 %>
46
+
47
+ A <%= exception.class.to_s %> occured: <%= exception.to_s %>
48
+
49
+ <%= exception.backtrace.select { |line| @backtrace_filter.call(line) }.join("\n") if exception.backtrace %>
50
+ EMAIL
51
+
52
+ class Middleware
53
+ def initialize(app, config = {})
54
+ @app = app
55
+ @notifier = ExceptionNo.new(config)
56
+ end
57
+
58
+ def call(env)
59
+ begin
60
+ @app.call(env)
61
+ rescue Exception => e
62
+ @notifier.notify(e, body: extract_env(env))
63
+
64
+ raise e
65
+ end
66
+ end
67
+
68
+ def extract_env(env)
69
+ req = Rack::Request.new(env)
70
+
71
+ parts = []
72
+
73
+ parts << "#{req.request_method} #{req.url}"
74
+ parts << "User-Agent: #{req.user_agent}" if req.user_agent
75
+ parts << "Referrer: #{req.referrer}" if req.referrer
76
+ parts << "Cookie: #{req.env["HTTP_COOKIE"]}" if req.cookies.size > 0
77
+
78
+ parts.join("\n")
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,67 @@
1
+ require_relative "prelude"
2
+
3
+ setup do
4
+ ExceptionNo.new(
5
+ host: "127.0.0.1",
6
+ port: 2525,
7
+ to: "root@localhost",
8
+ from: "service@localhost"
9
+ )
10
+ end
11
+
12
+ test "deliver exception notification" do |notifier|
13
+ ex = ArgumentError.new("Really bad argument")
14
+
15
+ notifier.notify(ex)
16
+
17
+ email = $smtp.outbox.last
18
+
19
+ assert_equal email[:to], "<root@localhost>"
20
+ assert_equal email[:from], "<service@localhost>"
21
+
22
+ headers, body = parse_email(email[:data])
23
+
24
+ assert_equal headers["Subject"], "ArgumentError: Really bad argument"
25
+ assert body.include?("A ArgumentError occured: Really bad argument")
26
+ end
27
+
28
+ test "exception messages with multiple lines" do |notifier|
29
+ notifier.notify(ArgumentError.new("A really\nbad\nargument"))
30
+
31
+ headers, body = parse_email($smtp.outbox.last[:data])
32
+
33
+ assert_equal headers["Subject"], "ArgumentError: A really bad argument"
34
+ end
35
+
36
+ test "includes backtrace information" do |notifier|
37
+ begin
38
+ raise ArgumentError, "A bad argument"
39
+ rescue Exception => ex
40
+ notifier.notify(ex)
41
+ end
42
+
43
+ headers, body = parse_email($smtp.outbox.last[:data])
44
+
45
+ assert body.include?(__FILE__)
46
+ assert body.include?(Gem.path.first)
47
+ end
48
+
49
+ test "allows to filter the backtrace" do |notifier|
50
+ notifier.backtrace_filter = -> line do
51
+ !line.include?(Gem.path.first)
52
+ end
53
+
54
+ begin
55
+ raise ArgumentError, "A bad argument"
56
+ rescue Exception => ex
57
+ notifier.notify(ex)
58
+ end
59
+
60
+ headers, body = parse_email($smtp.outbox.last[:data])
61
+
62
+ assert body.include?(__FILE__)
63
+ assert !body.include?(Gem.path.first)
64
+ end
65
+
66
+ $smtp.stop
67
+ $smtp.join
@@ -0,0 +1,66 @@
1
+ require_relative "prelude"
2
+
3
+ require "rack"
4
+
5
+ setup do
6
+ Rack::Builder.new do |builder|
7
+ builder.use ExceptionNo::Middleware,
8
+ host: "127.0.0.1",
9
+ port: 2525,
10
+ to: "root@localhost",
11
+ from: "service@localhost"
12
+
13
+ builder.run(-> env { 1 / 0 })
14
+ end
15
+ end
16
+
17
+ test "re-raises exceptions" do |app|
18
+ assert_raise(ZeroDivisionError) { app.call(Rack::MockRequest.env_for("/")) }
19
+ end
20
+
21
+ test "extracts interesting stuff from the request" do |app|
22
+ env = Rack::MockRequest.env_for(
23
+ "/baz",
24
+ "HTTP_USER_AGENT" => "Mozilla/4.0 (compatible)",
25
+ "HTTP_REFERER" => "/other",
26
+ "HTTP_COOKIE" => "foo=bar",
27
+ )
28
+
29
+ begin
30
+ app.call(env)
31
+ rescue ZeroDivisionError
32
+ end
33
+
34
+ headers, body = parse_email($smtp.outbox.last[:data])
35
+
36
+ assert_equal headers["Subject"], "ZeroDivisionError: divided by 0"
37
+ assert body.include?("GET http://example.org/baz")
38
+ assert body.include?("User-Agent: Mozilla/4.0 (compatible)")
39
+ assert body.include?("Referrer: /other")
40
+ assert body.include?("Cookie: foo=bar")
41
+ end
42
+
43
+ test "doesn't raise when the notification fails" do |app|
44
+ app = Rack::Builder.new do |builder|
45
+ builder.use ExceptionNo::Middleware,
46
+ host: "127.0.0.1",
47
+ port: 2526,
48
+ to: "root@localhost",
49
+ from: "service@localhost"
50
+
51
+ builder.run(-> env { 1 / 0 })
52
+ end
53
+
54
+ env = Rack::MockRequest.env_for(
55
+ "/baz",
56
+ "HTTP_USER_AGENT" => "Mozilla/4.0 (compatible)",
57
+ "HTTP_REFERER" => "/other",
58
+ "HTTP_COOKIE" => "foo=bar",
59
+ )
60
+
61
+ assert_raise(ZeroDivisionError) do
62
+ capture_stderr do
63
+ app.call(env)
64
+ end
65
+ end
66
+ end
data/test/prelude.rb ADDED
@@ -0,0 +1,62 @@
1
+ require "cutest"
2
+ require "mini-smtp-server"
3
+
4
+ require_relative "../lib/exception_no"
5
+
6
+ class SMTPServer < MiniSmtpServer
7
+ def outbox
8
+ @outbox ||= []
9
+ end
10
+
11
+ def new_message_event(message)
12
+ outbox << message
13
+ true
14
+ end
15
+ end
16
+
17
+ def parse_email(raw)
18
+ headers = {}
19
+ body = []
20
+ reading_body = false
21
+
22
+ raw.each_line do |line|
23
+ if !reading_body && line == "\r\n"
24
+ reading_body = true
25
+ next
26
+ end
27
+
28
+ if reading_body
29
+ body << line
30
+ else
31
+ key, value = line.split(": ", 2)
32
+ headers[key] = value && value.chomp
33
+ end
34
+ end
35
+
36
+ body.pop
37
+
38
+ return headers, body.join("").chomp
39
+ end
40
+
41
+ def capture_stderr
42
+ old, $stderr = $stderr, StringIO.new
43
+
44
+ begin
45
+ yield
46
+ ensure
47
+ $stderr = old
48
+ end
49
+ end
50
+
51
+ $smtp = SMTPServer.new(2525, "127.0.0.1")
52
+ $smtp.start
53
+
54
+ until SMTPServer.in_service?(2525)
55
+ end
56
+
57
+ at_exit do
58
+ if $smtp
59
+ $smtp.stop
60
+ $smtp.join
61
+ end
62
+ end
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: exception_no
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Educabilia
8
+ - Damian Janowski
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-09-17 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: mini-smtp-server
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ! '>='
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ! '>='
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: cutest
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ! '>='
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ! '>='
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ description:
43
+ email:
44
+ - opensource@educabilia.com
45
+ - djanowski@dimaion.com
46
+ executables: []
47
+ extensions: []
48
+ extra_rdoc_files: []
49
+ files:
50
+ - .gitignore
51
+ - Makefile
52
+ - exception_no.gemspec
53
+ - lib/exception_no.rb
54
+ - test/exception_no.rb
55
+ - test/middleware.rb
56
+ - test/prelude.rb
57
+ homepage: https://github.com/djanowski/exception_no
58
+ licenses: []
59
+ metadata: {}
60
+ post_install_message:
61
+ rdoc_options: []
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ! '>='
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ requirements: []
75
+ rubyforge_project:
76
+ rubygems_version: 2.0.0
77
+ signing_key:
78
+ specification_version: 4
79
+ summary: Truly basic exception notification.
80
+ test_files: []