asana_exception_notifier 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +1 -1
- data/lib/asana_exception_notifier/classes/asana.rb +39 -13
- data/lib/asana_exception_notifier/classes/error_page.rb +18 -8
- data/lib/asana_exception_notifier/helpers/application_helper.rb +20 -44
- data/lib/asana_exception_notifier/helpers/heredoc_helper.rb +30 -0
- data/lib/asana_exception_notifier/{note_templates/asana_exception_notifier.html.erb → templates/exception_details.html.erb} +0 -0
- data/lib/asana_exception_notifier/{note_templates/asana_exception_notifier.text.erb → templates/notes.text.erb} +0 -0
- data/lib/asana_exception_notifier/version.rb +1 -1
- data/spec/lib/asana_exception_notifier/classes/asana_spec.rb +0 -3
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3e9dd8cc08308fa3e912aa23314f1a5edd2d9f3e
|
4
|
+
data.tar.gz: 5b7599db7a424495bad6ceb7f32d78e577c86c78
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a1754feadb154011e8e833dee9456b8ba3beee6d7b5d41defb2ad6fed35ce4743926c0af8acd1e0757da652be07e46d98df61572711cf18be49187dd98666987
|
7
|
+
data.tar.gz: 66efa3e2561928c8de2b64a7a0ec77a407940f2e5634fb0864ea5dd6cc41ee23d76e08fe64d2a9fc28cee772e586971b6a6c291fdffa41aff060aba6d7880b40
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -8,7 +8,7 @@ Description
|
|
8
8
|
|
9
9
|
Simple ruby implementation to send notifications to Asana when a exception happens in Rails or Rack-based apps by creating a task and uploading exception details to the task
|
10
10
|
|
11
|
-
The gem provides a notifier for sending notifications to Asana when errors occur in a Rack/Rails application [courtesy of
|
11
|
+
The gem provides a notifier for sending notifications to Asana when errors occur in a Rack/Rails application [courtesy of exception_notification gem](https://github.com/smartinez87/exception_notification). Check out that gem for more details on setting up the rack middleware with additional options.
|
12
12
|
|
13
13
|
Requirements
|
14
14
|
------------
|
@@ -15,15 +15,14 @@ module ExceptionNotifier
|
|
15
15
|
def initialize(options)
|
16
16
|
execute_with_rescue do
|
17
17
|
super
|
18
|
-
@initial_options = options.symbolize_keys
|
19
|
-
|
20
|
-
parse_options(options)
|
18
|
+
@initial_options = options.symbolize_keys.reject { |_key, value| value.blank? }
|
19
|
+
parse_options(@initial_options)
|
21
20
|
end
|
22
21
|
end
|
23
22
|
|
24
23
|
def call(exception, options = {})
|
25
|
-
|
26
|
-
|
24
|
+
ensure_eventmachine_running do
|
25
|
+
execute_with_rescue do
|
27
26
|
EM::HttpRequest.use AsanaExceptionNotifier::Request::Middleware if ENV['DEBUG_ASANA_EXCEPTION_NOTIFIER']
|
28
27
|
error_page = AsanaExceptionNotifier::ErrorPage.new(template_path, exception, options)
|
29
28
|
create_asana_task(error_page) if active?
|
@@ -31,27 +30,54 @@ module ExceptionNotifier
|
|
31
30
|
end
|
32
31
|
end
|
33
32
|
|
33
|
+
def asana_api_key
|
34
|
+
@default_options.fetch(:asana_api_key, nil)
|
35
|
+
end
|
36
|
+
|
37
|
+
def workspace
|
38
|
+
@default_options.fetch(:workspace, nil)
|
39
|
+
end
|
40
|
+
|
41
|
+
def notes
|
42
|
+
@default_options.fetch(:notes, nil)
|
43
|
+
end
|
44
|
+
|
45
|
+
def task_name
|
46
|
+
@default_options.fetch(:name, nil)
|
47
|
+
end
|
48
|
+
|
34
49
|
def active?
|
35
|
-
|
50
|
+
asana_api_key.present? && workspace.present?
|
51
|
+
end
|
52
|
+
|
53
|
+
def template_path
|
54
|
+
@default_options.fetch(:template_path, nil)
|
36
55
|
end
|
37
56
|
|
38
57
|
private
|
39
58
|
|
40
59
|
def parse_options(options)
|
41
|
-
options = options.
|
60
|
+
options = options.reject { |key, _value| !permitted_options.key?(key) }
|
42
61
|
@default_options = permitted_options.merge(options).reject { |_key, value| value.blank? }
|
43
62
|
end
|
44
63
|
|
45
|
-
def
|
46
|
-
|
47
|
-
|
64
|
+
def note_content(error_page)
|
65
|
+
if path_is_a_template?(notes)
|
66
|
+
error_page.render_template(expanded_path(notes))
|
67
|
+
else
|
68
|
+
notes.present? ? notes : error_page.render_template(File.join(template_dir, 'notes.text.erb'))
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def task_name_content(error_page)
|
73
|
+
task_name.present? ? task_name : "[AsanaExceptionNotifier] #{error_page.exception_data[:message]}"
|
48
74
|
end
|
49
75
|
|
50
76
|
def build_request_options(error_page)
|
51
77
|
@default_options.except(:asana_api_key, :template_path).merge(
|
52
|
-
name:
|
53
|
-
notes:
|
54
|
-
workspace:
|
78
|
+
name: task_name_content(error_page),
|
79
|
+
notes: note_content(error_page),
|
80
|
+
workspace: workspace.to_i
|
55
81
|
).symbolize_keys!
|
56
82
|
end
|
57
83
|
|
@@ -7,9 +7,9 @@ module AsanaExceptionNotifier
|
|
7
7
|
attr_reader :template_path, :exception, :options, :boundary, :template_details, :env, :request, :tempfile, :template_params, :content
|
8
8
|
|
9
9
|
def initialize(template_path, exception, options)
|
10
|
-
@template_path = template_path
|
11
10
|
@exception = exception
|
12
11
|
@options = options.symbolize_keys
|
12
|
+
html_template(template_path)
|
13
13
|
@template_details = setup_template_details
|
14
14
|
@env = (@options[:env] || ENV.to_h).stringify_keys
|
15
15
|
@request = action_dispatch? ? ActionDispatch::Request.new(@env) : Rack::Request.new(@env)
|
@@ -17,6 +17,14 @@ module AsanaExceptionNotifier
|
|
17
17
|
parse_exception_options
|
18
18
|
end
|
19
19
|
|
20
|
+
def html_template(path)
|
21
|
+
@template_path = if path_is_a_template?(path)
|
22
|
+
expanded_path(path)
|
23
|
+
else
|
24
|
+
File.join(template_dir, 'exception_details.html.erb')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
20
28
|
def action_dispatch?
|
21
29
|
defined?(ActionDispatch::Request)
|
22
30
|
end
|
@@ -110,17 +118,19 @@ module AsanaExceptionNotifier
|
|
110
118
|
def create_tempfile(output = render_template)
|
111
119
|
tempfile = Tempfile.new([SecureRandom.uuid, ".#{@template_details[:template_extension]}"], encoding: 'utf-8')
|
112
120
|
tempfile.write(output)
|
121
|
+
ObjectSpace.undefine_finalizer(tempfile) # force garbage collector not to remove automatically the file
|
113
122
|
tempfile.close
|
114
|
-
|
115
|
-
[details[:filename], details[:path]]
|
123
|
+
tempfile_details(tempfile).slice(:filename, :path).values
|
116
124
|
end
|
117
125
|
|
118
126
|
def fetch_archives(output = render_template)
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
127
|
+
execute_with_rescue(value: []) do
|
128
|
+
return [] if output.blank?
|
129
|
+
filename, path = create_tempfile(output)
|
130
|
+
archive = compress_files(File.dirname(path), filename, [expanded_path(path)])
|
131
|
+
remove_tempfile(path)
|
132
|
+
split_archive(archive, "part_#{filename}", 1024 * 1024 * 100)
|
133
|
+
end
|
124
134
|
end
|
125
135
|
|
126
136
|
def remove_tempfile(path)
|
@@ -1,6 +1,8 @@
|
|
1
|
+
require_relative './heredoc_helper'
|
1
2
|
module AsanaExceptionNotifier
|
2
3
|
# module that is used for formatting numbers using metrics
|
3
4
|
module ApplicationHelper
|
5
|
+
include AsanaExceptionNotifier::HeredocHelper
|
4
6
|
# function that makes the methods incapsulated as utility functions
|
5
7
|
|
6
8
|
module_function
|
@@ -21,25 +23,28 @@ module AsanaExceptionNotifier
|
|
21
23
|
tags: [],
|
22
24
|
notes: '',
|
23
25
|
name: '',
|
24
|
-
template_path:
|
26
|
+
template_path: nil
|
25
27
|
}
|
26
28
|
end
|
27
29
|
|
30
|
+
def expanded_path(path)
|
31
|
+
File.expand_path(path)
|
32
|
+
end
|
33
|
+
|
34
|
+
def path_is_a_template?(path)
|
35
|
+
path.present? && template_path_exist(expanded_path(path))
|
36
|
+
end
|
37
|
+
|
28
38
|
def multi_request_manager
|
29
39
|
@multi_manager ||= EventMachine::MultiRequest.new
|
30
40
|
end
|
31
41
|
|
32
|
-
def extract_body(
|
33
|
-
return
|
34
|
-
io
|
35
|
-
io.rewind if io.respond_to?(:rewind)
|
42
|
+
def extract_body(io)
|
43
|
+
return unless io.respond_to?(:rewind)
|
44
|
+
io.rewind
|
36
45
|
io.read
|
37
|
-
|
38
|
-
|
39
|
-
def show_hash_content(hash)
|
40
|
-
hash.map do |key, value|
|
41
|
-
value.is_a?(Hash) ? show_hash_content(value) : ["#{key}:", value]
|
42
|
-
end.join("\n ")
|
46
|
+
rescue
|
47
|
+
io.inspect
|
43
48
|
end
|
44
49
|
|
45
50
|
def tempfile_details(tempfile)
|
@@ -111,11 +116,7 @@ module AsanaExceptionNotifier
|
|
111
116
|
end
|
112
117
|
|
113
118
|
def template_dir
|
114
|
-
File.expand_path(File.join(root, '
|
115
|
-
end
|
116
|
-
|
117
|
-
def default_template_path
|
118
|
-
File.join(template_dir, 'asana_exception_notifier.html.erb')
|
119
|
+
File.expand_path(File.join(root, 'templates'))
|
119
120
|
end
|
120
121
|
|
121
122
|
def template_path_exist(path)
|
@@ -123,26 +124,19 @@ module AsanaExceptionNotifier
|
|
123
124
|
fail ArgumentError, "file #{path} doesn't exist"
|
124
125
|
end
|
125
126
|
|
126
|
-
def max_length(rows, index)
|
127
|
-
value = rows.max_by { |array| array[index].to_s.size }
|
128
|
-
value.is_a?(Array) ? value[index] : value
|
129
|
-
end
|
130
|
-
|
131
127
|
def get_hash_rows(hash, rows = [], prefix = '')
|
132
128
|
hash.each do |key, value|
|
133
129
|
if value.is_a?(Hash)
|
134
130
|
get_hash_rows(value, rows, key)
|
135
131
|
else
|
136
|
-
rows.push(["#{prefix}#{key}".inspect, escape(value.inspect)])
|
132
|
+
rows.push(["#{prefix}#{key}".inspect, escape(inspect_value(value).inspect)])
|
137
133
|
end
|
138
134
|
end
|
139
135
|
rows
|
140
136
|
end
|
141
137
|
|
142
|
-
def
|
143
|
-
|
144
|
-
<a href="javascript:void(0)" onclick="AjaxExceptionNotifier.hideAllAndToggle('#{link.downcase}')">#{link.camelize}</a>
|
145
|
-
LINK
|
138
|
+
def inspect_value(value)
|
139
|
+
value.is_a?(IO) ? extract_body(value) : value
|
146
140
|
end
|
147
141
|
|
148
142
|
def escape(text)
|
@@ -159,24 +153,6 @@ module AsanaExceptionNotifier
|
|
159
153
|
value.is_a?(Hash) ? value.reject! { |_new_key, new_value| new_value.is_a?(Hash) } : value
|
160
154
|
end
|
161
155
|
|
162
|
-
# Gets a bidimensional array and create a table.
|
163
|
-
# The first array is used as label.
|
164
|
-
#
|
165
|
-
def mount_table(array, options = {})
|
166
|
-
return '' if array.blank?
|
167
|
-
header = array.shift
|
168
|
-
|
169
|
-
header = header.map { |name| escape(name.to_s.humanize) }
|
170
|
-
rows = array.map { |name| "<tr><td>#{name.join('</td><td>')}</td></tr>" }
|
171
|
-
|
172
|
-
<<-TABLE
|
173
|
-
<table #{hash_to_html_attributes(options)}>
|
174
|
-
<thead><tr><th>#{header.join('</th><th>')}</th></tr></thead>
|
175
|
-
<tbody>#{rows.join}</tbody>
|
176
|
-
</table>
|
177
|
-
TABLE
|
178
|
-
end
|
179
|
-
|
180
156
|
# Mount table for hash, using name and value and adding a name_value class
|
181
157
|
# to the generated table.
|
182
158
|
#
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module AsanaExceptionNotifier
|
2
|
+
# helper methods that use Heredoc syntax
|
3
|
+
module HeredocHelper
|
4
|
+
module_function
|
5
|
+
|
6
|
+
def link_helper(link)
|
7
|
+
<<-HTML
|
8
|
+
<a href="javascript:void(0)" onclick="AjaxExceptionNotifier.hideAllAndToggle('#{link.downcase}')">#{link.camelize}</a>
|
9
|
+
HTML
|
10
|
+
end
|
11
|
+
|
12
|
+
# Gets a bidimensional array and create a table.
|
13
|
+
# The first array is used as label.
|
14
|
+
#
|
15
|
+
def mount_table(array, options = {})
|
16
|
+
return '' if array.blank?
|
17
|
+
header = array.shift
|
18
|
+
|
19
|
+
header = header.map { |name| escape(name.to_s.humanize) }
|
20
|
+
rows = array.map { |name| "<tr><td>#{name.join('</td><td>')}</td></tr>" }
|
21
|
+
|
22
|
+
<<-HTML
|
23
|
+
<table #{hash_to_html_attributes(options)}>
|
24
|
+
<thead><tr><th>#{header.join('</th><th>')}</th></tr></thead>
|
25
|
+
<tbody>#{rows.join}</tbody>
|
26
|
+
</table>
|
27
|
+
HTML
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
File without changes
|
File without changes
|
@@ -3,7 +3,6 @@
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
5
|
describe ExceptionNotifier::AsanaNotifier do
|
6
|
-
|
7
6
|
let(:options) { double('options') }
|
8
7
|
|
9
8
|
before(:each) do
|
@@ -18,6 +17,4 @@ describe ExceptionNotifier::AsanaNotifier do
|
|
18
17
|
expect(@subject.initial_options).to eq options
|
19
18
|
end
|
20
19
|
end
|
21
|
-
|
22
|
-
|
23
20
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: asana_exception_notifier
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- bogdanRada
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-02-
|
11
|
+
date: 2016-02-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -420,12 +420,13 @@ files:
|
|
420
420
|
- lib/asana_exception_notifier/classes/asana.rb
|
421
421
|
- lib/asana_exception_notifier/classes/error_page.rb
|
422
422
|
- lib/asana_exception_notifier/helpers/application_helper.rb
|
423
|
+
- lib/asana_exception_notifier/helpers/heredoc_helper.rb
|
423
424
|
- lib/asana_exception_notifier/initializers/zip.rb
|
424
|
-
- lib/asana_exception_notifier/note_templates/asana_exception_notifier.html.erb
|
425
|
-
- lib/asana_exception_notifier/note_templates/asana_exception_notifier.text.erb
|
426
425
|
- lib/asana_exception_notifier/request/client.rb
|
427
426
|
- lib/asana_exception_notifier/request/core.rb
|
428
427
|
- lib/asana_exception_notifier/request/middleware.rb
|
428
|
+
- lib/asana_exception_notifier/templates/exception_details.html.erb
|
429
|
+
- lib/asana_exception_notifier/templates/notes.text.erb
|
429
430
|
- lib/asana_exception_notifier/version.rb
|
430
431
|
- lib/generators/asana_exception_notifier/install_generator.rb
|
431
432
|
- lib/generators/asana_exception_notifier/templates/asana_exception_notifier.rb
|