asana_exception_notifier 0.0.3 → 0.0.4
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 +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
|