asana_exception_notifier 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.codeclimate.yml +26 -0
- data/.reek +11 -0
- data/.rubocop.yml +76 -0
- data/.travis.yml +16 -0
- data/CONTRIBUTING.md +46 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +180 -0
- data/LICENSE +20 -0
- data/README.md +225 -0
- data/Rakefile +37 -0
- data/asana_exception_notifier.gemspec +48 -0
- data/examples/sinatra/Gemfile +7 -0
- data/examples/sinatra/Gemfile.lock +124 -0
- data/examples/sinatra/Procfile +1 -0
- data/examples/sinatra/README.md +14 -0
- data/examples/sinatra/config.ru +3 -0
- data/examples/sinatra/sinatra_app.rb +46 -0
- data/init.rb +1 -0
- data/lib/asana_exception_notifier/classes/asana.rb +95 -0
- data/lib/asana_exception_notifier/classes/error_page.rb +134 -0
- data/lib/asana_exception_notifier/helpers/application_helper.rb +286 -0
- data/lib/asana_exception_notifier/initializers/zip.rb +14 -0
- data/lib/asana_exception_notifier/note_templates/asana_exception_notifier.html.erb +82 -0
- data/lib/asana_exception_notifier/note_templates/asana_exception_notifier.text.erb +24 -0
- data/lib/asana_exception_notifier/request/client.rb +85 -0
- data/lib/asana_exception_notifier/request/core.rb +132 -0
- data/lib/asana_exception_notifier/request/middleware.rb +41 -0
- data/lib/asana_exception_notifier/version.rb +27 -0
- data/lib/asana_exception_notifier.rb +45 -0
- data/lib/generators/asana_exception_notifier/install_generator.rb +14 -0
- data/lib/generators/asana_exception_notifier/templates/asana_exception_notifier.rb +20 -0
- data/spec/lib/asana_exception_notifier/classes/asana_spec.rb +23 -0
- data/spec/spec_helper.rb +45 -0
- data/spec/test_notification.rb +20 -0
- metadata +467 -0
data/Rakefile
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'bundler/gem_tasks'
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
require 'coveralls/rake/task'
|
5
|
+
require 'yard'
|
6
|
+
Coveralls::RakeTask.new
|
7
|
+
|
8
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
9
|
+
default_options = ['--colour']
|
10
|
+
default_options.concat(['--backtrace', '--fail-fast']) if ENV['DEBUG']
|
11
|
+
spec.rspec_opts = default_options
|
12
|
+
end
|
13
|
+
|
14
|
+
YARD::Config.options[:load_plugins] = true
|
15
|
+
YARD::Config.load_plugins
|
16
|
+
|
17
|
+
YARD::Rake::YardocTask.new do |t|
|
18
|
+
t.files = ['lib/**/*.rb', 'spec/**/*_spec.rb'] # optional
|
19
|
+
t.options = ['--any', '--extra', '--opts', '--markup-provider=redcarpet', '--markup=markdown', '--debug'] # optional
|
20
|
+
t.stats_options = ['--list-undoc'] # optional
|
21
|
+
end
|
22
|
+
|
23
|
+
desc 'Default: run the unit tests.'
|
24
|
+
task default: [:all]
|
25
|
+
|
26
|
+
desc 'Test the plugin under all supported Rails versions.'
|
27
|
+
task :all do |_t|
|
28
|
+
if ENV['TRAVIS']
|
29
|
+
exec('bundle exec rake spec && bundle exec rake coveralls:push')
|
30
|
+
else
|
31
|
+
exec('bundle exec rake spec')
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
task :docs do
|
36
|
+
exec('bundle exec inch --pedantic && bundle exec yard --list-undoc')
|
37
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require File.expand_path('../lib/asana_exception_notifier/version', __FILE__)
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = 'asana_exception_notifier'
|
5
|
+
s.version = AsanaExceptionNotifier.gem_version
|
6
|
+
s.platform = Gem::Platform::RUBY
|
7
|
+
s.summary = 'Simple ruby implementation to send notifications to Asana
|
8
|
+
when a exception happens in Rails or Rack-based apps by creating a task and uploading exception details to the task'
|
9
|
+
s.email = 'raoul_ice@yahoo.com'
|
10
|
+
s.homepage = 'http://github.com/bogdanRada/asana_exception_notifier'
|
11
|
+
s.description = 'Simple ruby implementation to send notifications to Asana
|
12
|
+
when a exception happens in Rails or Rack-based apps by creating a task and uploading exception details to the task using zip archives'
|
13
|
+
s.authors = ['bogdanRada']
|
14
|
+
s.date = Date.today
|
15
|
+
|
16
|
+
s.licenses = ['MIT']
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = s.files.grep(/^(spec)/)
|
19
|
+
s.require_paths = ['lib']
|
20
|
+
|
21
|
+
s.required_ruby_version = '>= 2.0'
|
22
|
+
s.required_rubygems_version = '>= 2.5'
|
23
|
+
s.metadata = {
|
24
|
+
'source_code' => s.homepage,
|
25
|
+
'bug_tracker' => "#{s.homepage}/issues"
|
26
|
+
}
|
27
|
+
|
28
|
+
s.add_runtime_dependency 'activesupport', '>= 4.0', '< 5'
|
29
|
+
s.add_runtime_dependency 'em-http-request', '~> 1.1', '>= 1.1.2'
|
30
|
+
s.add_runtime_dependency 'eventmachine', '~> 1.0', '>= 1.0.7'
|
31
|
+
s.add_runtime_dependency 'exception_notification', '~> 4.1', '>= 4.1.4'
|
32
|
+
s.add_runtime_dependency 'multipart_body', '~> 0.2', '>= 0.2.1'
|
33
|
+
s.add_runtime_dependency 'tilt', '>= 1.4', '< 3'
|
34
|
+
s.add_runtime_dependency 'rack', '~> 1.6', '>= 1.6'
|
35
|
+
s.add_runtime_dependency 'rubyzip', '~> 1.0', '>= 1.0.0' # will load new rubyzip version
|
36
|
+
s.add_runtime_dependency 'zip-zip', '~> 0.3', '>= 0.3' # will load compatibility for old rubyzip API
|
37
|
+
s.add_runtime_dependency 'sys-uname', '~> 1.0', '>= 1.0.2'
|
38
|
+
|
39
|
+
s.add_development_dependency 'rspec', '~> 3.4', '>= 3.4'
|
40
|
+
s.add_development_dependency 'simplecov', '~> 0.10', '>= 0.10'
|
41
|
+
s.add_development_dependency 'simplecov-summary', '~> 0.0.4', '>= 0.0.4'
|
42
|
+
s.add_development_dependency 'coveralls', '~> 0.7', '>= 0.7'
|
43
|
+
s.add_development_dependency 'rake', '~> 10.5', '>= 10.5'
|
44
|
+
s.add_development_dependency 'yard', '~> 0.8', '>= 0.8.7'
|
45
|
+
s.add_development_dependency 'redcarpet', '~> 3.3', '>= 3.3'
|
46
|
+
s.add_development_dependency 'github-markup', '~> 1.3', '>= 1.3.3'
|
47
|
+
s.add_development_dependency 'inch', '~> 0.6', '>= 0.6'
|
48
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
PATH
|
2
|
+
remote: ../../
|
3
|
+
specs:
|
4
|
+
asana_exception_notifier (0.0.1)
|
5
|
+
activesupport (>= 4.0, < 5)
|
6
|
+
em-http-request (~> 1.1, >= 1.1.2)
|
7
|
+
eventmachine (~> 1.0, >= 1.0.7)
|
8
|
+
exception_notification (~> 4.1, >= 4.1.4)
|
9
|
+
multipart_body (~> 0.2, >= 0.2.1)
|
10
|
+
rack (~> 1.6, >= 1.6)
|
11
|
+
rubyzip (~> 1.0, >= 1.0.0)
|
12
|
+
sys-uname (~> 1.0, >= 1.0.2)
|
13
|
+
tilt (>= 1.4, < 3)
|
14
|
+
zip-zip (~> 0.3, >= 0.3)
|
15
|
+
|
16
|
+
GEM
|
17
|
+
remote: https://rubygems.org/
|
18
|
+
specs:
|
19
|
+
actionmailer (4.2.5.1)
|
20
|
+
actionpack (= 4.2.5.1)
|
21
|
+
actionview (= 4.2.5.1)
|
22
|
+
activejob (= 4.2.5.1)
|
23
|
+
mail (~> 2.5, >= 2.5.4)
|
24
|
+
rails-dom-testing (~> 1.0, >= 1.0.5)
|
25
|
+
actionpack (4.2.5.1)
|
26
|
+
actionview (= 4.2.5.1)
|
27
|
+
activesupport (= 4.2.5.1)
|
28
|
+
rack (~> 1.6)
|
29
|
+
rack-test (~> 0.6.2)
|
30
|
+
rails-dom-testing (~> 1.0, >= 1.0.5)
|
31
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
32
|
+
actionview (4.2.5.1)
|
33
|
+
activesupport (= 4.2.5.1)
|
34
|
+
builder (~> 3.1)
|
35
|
+
erubis (~> 2.7.0)
|
36
|
+
rails-dom-testing (~> 1.0, >= 1.0.5)
|
37
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
38
|
+
activejob (4.2.5.1)
|
39
|
+
activesupport (= 4.2.5.1)
|
40
|
+
globalid (>= 0.3.0)
|
41
|
+
activesupport (4.2.5.1)
|
42
|
+
i18n (~> 0.7)
|
43
|
+
json (~> 1.7, >= 1.7.7)
|
44
|
+
minitest (~> 5.1)
|
45
|
+
thread_safe (~> 0.3, >= 0.3.4)
|
46
|
+
tzinfo (~> 1.1)
|
47
|
+
addressable (2.4.0)
|
48
|
+
builder (3.2.2)
|
49
|
+
cookiejar (0.3.0)
|
50
|
+
daemons (1.2.3)
|
51
|
+
em-http-request (1.1.3)
|
52
|
+
addressable (>= 2.3.4)
|
53
|
+
cookiejar (<= 0.3.0)
|
54
|
+
em-socksify (>= 0.3)
|
55
|
+
eventmachine (>= 1.0.3)
|
56
|
+
http_parser.rb (>= 0.6.0)
|
57
|
+
em-socksify (0.3.1)
|
58
|
+
eventmachine (>= 1.0.0.beta.4)
|
59
|
+
erubis (2.7.0)
|
60
|
+
eventmachine (1.0.9.1)
|
61
|
+
exception_notification (4.1.4)
|
62
|
+
actionmailer (~> 4.0)
|
63
|
+
activesupport (~> 4.0)
|
64
|
+
ffi (1.9.10)
|
65
|
+
foreman (0.78.0)
|
66
|
+
thor (~> 0.19.1)
|
67
|
+
globalid (0.3.6)
|
68
|
+
activesupport (>= 4.1.0)
|
69
|
+
http_parser.rb (0.6.0)
|
70
|
+
i18n (0.7.0)
|
71
|
+
json (1.8.3)
|
72
|
+
loofah (2.0.3)
|
73
|
+
nokogiri (>= 1.5.9)
|
74
|
+
mail (2.6.3)
|
75
|
+
mime-types (>= 1.16, < 3)
|
76
|
+
mime-types (2.99)
|
77
|
+
mini_portile2 (2.0.0)
|
78
|
+
minitest (5.8.4)
|
79
|
+
multipart_body (0.2.1)
|
80
|
+
nokogiri (1.6.7.2)
|
81
|
+
mini_portile2 (~> 2.0.0.rc2)
|
82
|
+
rack (1.6.4)
|
83
|
+
rack-protection (1.5.3)
|
84
|
+
rack
|
85
|
+
rack-test (0.6.3)
|
86
|
+
rack (>= 1.0)
|
87
|
+
rails-deprecated_sanitizer (1.0.3)
|
88
|
+
activesupport (>= 4.2.0.alpha)
|
89
|
+
rails-dom-testing (1.0.7)
|
90
|
+
activesupport (>= 4.2.0.beta, < 5.0)
|
91
|
+
nokogiri (~> 1.6.0)
|
92
|
+
rails-deprecated_sanitizer (>= 1.0.1)
|
93
|
+
rails-html-sanitizer (1.0.3)
|
94
|
+
loofah (~> 2.0)
|
95
|
+
rubyzip (1.1.7)
|
96
|
+
sinatra (1.4.7)
|
97
|
+
rack (~> 1.5)
|
98
|
+
rack-protection (~> 1.4)
|
99
|
+
tilt (>= 1.3, < 3)
|
100
|
+
sys-uname (1.0.2)
|
101
|
+
ffi (>= 1.0.0)
|
102
|
+
thin (1.5.1)
|
103
|
+
daemons (>= 1.0.9)
|
104
|
+
eventmachine (>= 0.12.6)
|
105
|
+
rack (>= 1.0.0)
|
106
|
+
thor (0.19.1)
|
107
|
+
thread_safe (0.3.5)
|
108
|
+
tilt (2.0.2)
|
109
|
+
tzinfo (1.2.2)
|
110
|
+
thread_safe (~> 0.1)
|
111
|
+
zip-zip (0.3)
|
112
|
+
rubyzip (>= 1.0.0)
|
113
|
+
|
114
|
+
PLATFORMS
|
115
|
+
ruby
|
116
|
+
|
117
|
+
DEPENDENCIES
|
118
|
+
asana_exception_notifier!
|
119
|
+
foreman
|
120
|
+
sinatra (~> 1.4)
|
121
|
+
thin (~> 1.5.1)
|
122
|
+
|
123
|
+
BUNDLED WITH
|
124
|
+
1.11.2
|
@@ -0,0 +1 @@
|
|
1
|
+
web: bundle exec thin start --port 3000
|
@@ -0,0 +1,14 @@
|
|
1
|
+
Using Exception Notification with Sinatra
|
2
|
+
=========================================
|
3
|
+
|
4
|
+
Quick start
|
5
|
+
-----------
|
6
|
+
|
7
|
+
```
|
8
|
+
git clone git@github.com:bogdanRada/asana_exception_notifier.git
|
9
|
+
cd exception_notification/examples/sinatra
|
10
|
+
bundle install
|
11
|
+
bundle exec foreman start
|
12
|
+
```
|
13
|
+
|
14
|
+
The last command starts the sinatra app itself. Thus, visit [http://localhost:1080/](http://localhost:1080/) to check the asana notification is sent and, in a separated tab, visit [Asana.com](http://asana.com) and cause some errors. For more info, use the [source](https://github.com/bogdanRada/asana_exception_notifier/blob/master/examples/sinatra/sinatra_app.rb).
|
@@ -0,0 +1,46 @@
|
|
1
|
+
$stdout.sync = true
|
2
|
+
require 'rubygems'
|
3
|
+
require 'bundler'
|
4
|
+
require 'bundler/setup'
|
5
|
+
ENV['RACK_ENV'] ||= ENV['RAILS_ENV'].present? ? ENV['RAILS_ENV'] : 'development'
|
6
|
+
Bundler.require :default, (ENV['RACK_ENV'] || 'development').to_sym
|
7
|
+
|
8
|
+
|
9
|
+
class SinatraApp < Sinatra::Base
|
10
|
+
use Rack::Config do |env|
|
11
|
+
env["action_dispatch.parameter_filter"] = [:password] # This is highly recommended. It will prevent the ExceptionNotification email from including your users' passwords
|
12
|
+
end
|
13
|
+
|
14
|
+
use ExceptionNotification::Rack,
|
15
|
+
:asana => {
|
16
|
+
asana_api_key: ENV['ASANA_API_KEY'],
|
17
|
+
workspace: ENV['ASANA_WORKSPACE_ID'],
|
18
|
+
assignee: 'me',
|
19
|
+
assignee_status: 'today', # 'today'
|
20
|
+
due_at: Time.now.iso8601,
|
21
|
+
due_on: nil,
|
22
|
+
hearted: false,
|
23
|
+
hearts: [],
|
24
|
+
projects: [],
|
25
|
+
followers: [],
|
26
|
+
memberships: [],
|
27
|
+
tags: [],
|
28
|
+
name: nil,
|
29
|
+
notes: '',
|
30
|
+
template_path: nil
|
31
|
+
}
|
32
|
+
|
33
|
+
get '/' do
|
34
|
+
raise StandardError, "ERROR: #{params[:error]}" unless params[:error].blank?
|
35
|
+
'Everything is fine! Now, lets break things clicking <a href="/?error=ops"> here </a>. Dont forget to see the asana tasks at <a href="http://asana.com">Asana</a> !'
|
36
|
+
end
|
37
|
+
|
38
|
+
get '/background_notification' do
|
39
|
+
begin
|
40
|
+
1/0
|
41
|
+
rescue Exception => e
|
42
|
+
ExceptionNotifier.notify_exception(e, :data => {:msg => "Cannot divide by zero!"})
|
43
|
+
end
|
44
|
+
'Check notification at <a href="http://asana.com">Asana</a>.'
|
45
|
+
end
|
46
|
+
end
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'asana_exception_notifier'
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require_relative '../helpers/application_helper'
|
2
|
+
require_relative '../request/client'
|
3
|
+
require_relative '../request/middleware'
|
4
|
+
# class used for connecting to github api and retrieves information about repository
|
5
|
+
#
|
6
|
+
# @!attribute callback
|
7
|
+
# @return [Proc] The callback that is executed after the info is fetched from Github API
|
8
|
+
module ExceptionNotifier
|
9
|
+
# module that is used for formatting numbers using metrics
|
10
|
+
class AsanaNotifier < ExceptionNotifier::BaseNotifier
|
11
|
+
include AsanaExceptionNotifier::ApplicationHelper
|
12
|
+
# the base url to which the API will connect for fetching information about gems
|
13
|
+
attr_reader :initial_options, :default_options
|
14
|
+
|
15
|
+
def initialize(options)
|
16
|
+
execute_with_rescue do
|
17
|
+
super
|
18
|
+
@initial_options = options.symbolize_keys
|
19
|
+
options = @initial_options.reject { |_key, value| value.blank? }
|
20
|
+
parse_options(options)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def call(exception, options = {})
|
25
|
+
execute_with_rescue do
|
26
|
+
ensure_eventmachine_running do
|
27
|
+
EM::HttpRequest.use AsanaExceptionNotifier::Request::Middleware if ENV['DEBUG_ASANA_EXCEPTION_NOTIFIER']
|
28
|
+
error_page = AsanaExceptionNotifier::ErrorPage.new(template_path, exception, options)
|
29
|
+
create_asana_task(error_page) if active?
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def active?
|
35
|
+
@default_options.fetch(:asana_api_key, nil).present? && @default_options.fetch(:workspace, nil).present?
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def parse_options(options)
|
41
|
+
options = options.symbolize_keys.reject { |key, _value| !permitted_options.key?(key) }
|
42
|
+
@default_options = permitted_options.merge(options).reject { |_key, value| value.blank? }
|
43
|
+
end
|
44
|
+
|
45
|
+
def template_path
|
46
|
+
template_path = @default_options.fetch(:template_path, nil)
|
47
|
+
template_path.blank? ? default_template_path : template_path_exist(File.expand_path(template_path))
|
48
|
+
end
|
49
|
+
|
50
|
+
def build_request_options(error_page)
|
51
|
+
@default_options.except(:asana_api_key, :template_path).merge(
|
52
|
+
name: @default_options.fetch(:name, nil) || "[AsanaExceptionNotifier] #{error_page.exception_data[:message]}",
|
53
|
+
notes: @default_options.fetch(:notes, nil) || error_page.render_template(File.join(template_dir, 'asana_exception_notifier.text.erb')),
|
54
|
+
workspace: @default_options.fetch(:workspace, nil).to_i
|
55
|
+
).symbolize_keys!
|
56
|
+
end
|
57
|
+
|
58
|
+
# This method fetches data from Github api and returns the size in
|
59
|
+
#
|
60
|
+
# @return [void]
|
61
|
+
def create_asana_task(error_page)
|
62
|
+
AsanaExceptionNotifier::Request::Client.new(@default_options.fetch(:asana_api_key, nil),
|
63
|
+
'https://app.asana.com/api/1.0/tasks',
|
64
|
+
'http_method' => 'post',
|
65
|
+
'em_request' => { body: build_request_options(error_page) },
|
66
|
+
'action' => 'creation'
|
67
|
+
) do |http_response|
|
68
|
+
ensure_eventmachine_running do
|
69
|
+
upload_log_file_to_task(error_page, http_response.fetch('data', {}))
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def upload_log_file_to_task(error_page, task_data)
|
75
|
+
archives = error_page.fetch_archives
|
76
|
+
archives.each do |zip|
|
77
|
+
upload_archive(zip, task_data)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def upload_archive(zip, task_data)
|
82
|
+
return if task_data.blank?
|
83
|
+
body = multipart_file_upload_details(zip)
|
84
|
+
AsanaExceptionNotifier::Request::Client.new(@default_options.fetch(:asana_api_key, nil),
|
85
|
+
"https://app.asana.com/api/1.0/tasks/#{task_data['id']}/attachments",
|
86
|
+
'http_method' => 'post',
|
87
|
+
'em_request' => body,
|
88
|
+
'request_name' => zip,
|
89
|
+
'action' => 'upload'
|
90
|
+
) do |_http_response|
|
91
|
+
FileUtils.rm_rf([zip])
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
require_relative '../helpers/application_helper'
|
2
|
+
module AsanaExceptionNotifier
|
3
|
+
# class used for rendering the template for exception
|
4
|
+
class ErrorPage
|
5
|
+
include AsanaExceptionNotifier::ApplicationHelper
|
6
|
+
|
7
|
+
attr_reader :template_path, :exception, :options, :boundary, :template_details, :env, :request, :tempfile, :template_params, :content
|
8
|
+
|
9
|
+
def initialize(template_path, exception, options)
|
10
|
+
@template_path = template_path
|
11
|
+
@exception = exception
|
12
|
+
@options = options.symbolize_keys
|
13
|
+
@template_details = setup_template_details
|
14
|
+
@env = (@options[:env] || ENV.to_h).stringify_keys
|
15
|
+
@request = action_dispatch? ? ActionDispatch::Request.new(@env) : Rack::Request.new(@env)
|
16
|
+
@timestamp = Time.now
|
17
|
+
parse_exception_options
|
18
|
+
end
|
19
|
+
|
20
|
+
def action_dispatch?
|
21
|
+
defined?(ActionDispatch::Request)
|
22
|
+
end
|
23
|
+
|
24
|
+
def setup_template_details
|
25
|
+
template_extension = @template_path.scan(/\.(\w+)\.?(.*)?/)[0][0]
|
26
|
+
get_extension_and_name_from_file(@template_path).merge(
|
27
|
+
template_extension: template_extension
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
def parse_exception_options
|
32
|
+
@template_params ||= {
|
33
|
+
server: Socket.gethostname,
|
34
|
+
exception: @exception,
|
35
|
+
request: @request,
|
36
|
+
environment: action_dispatch? ? @request.filtered_env : @env,
|
37
|
+
rails_root: defined?(Rails) ? Rails.root : nil,
|
38
|
+
process: $PROCESS_ID,
|
39
|
+
data: (@env.blank? ? {} : @env.fetch(:'exception_notifier.exception_data', {})).merge(@options[:data] || {}),
|
40
|
+
exception_data: exception_data,
|
41
|
+
request_data: setup_env_params,
|
42
|
+
uname: Sys::Uname.uname,
|
43
|
+
timestamp: @timestamp,
|
44
|
+
pwd: File.expand_path($PROGRAM_NAME)
|
45
|
+
}.merge(@options).reject { |_key, value| value.blank? }
|
46
|
+
end
|
47
|
+
|
48
|
+
def exception_data
|
49
|
+
{
|
50
|
+
error_class: @exception.class.to_s,
|
51
|
+
message: @exception.respond_to?(:message) ? @exception.message : exception.inspect,
|
52
|
+
backtrace: @exception.respond_to?(:backtrace) ? @exception.backtrace : '',
|
53
|
+
cause: @exception.respond_to?(:cause) ? @exception.cause : ''
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
def setup_env_params
|
58
|
+
{
|
59
|
+
url: action_dispatch? ? @request.original_url : @request.path_info,
|
60
|
+
referrer: @request.referer,
|
61
|
+
http_method: action_dispatch? ? @request.method : @request.request_method,
|
62
|
+
ip_address: action_dispatch? ? @request.remote_ip : @request.ip,
|
63
|
+
parameters: action_dispatch? ? @request.filtered_parameters : request_params,
|
64
|
+
session: @request.session,
|
65
|
+
cookies: @request.cookies,
|
66
|
+
user_agent: @request.user_agent
|
67
|
+
}
|
68
|
+
end
|
69
|
+
|
70
|
+
def request_params
|
71
|
+
@request.params
|
72
|
+
rescue
|
73
|
+
{}
|
74
|
+
end
|
75
|
+
|
76
|
+
def fieldsets_links
|
77
|
+
fieldsets.map { |key, _value| link_helper(key.to_s) }.join(' | ')
|
78
|
+
end
|
79
|
+
|
80
|
+
def fetch_fieldsets(hash, links = {}, prefix = nil)
|
81
|
+
return unless hash.is_a?(Hash)
|
82
|
+
hash.each do |key, value|
|
83
|
+
if value.is_a?(Hash)
|
84
|
+
fetch_fieldsets(value, links, key)
|
85
|
+
else
|
86
|
+
add_to_links(links, prefix, key: key, value: value)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
links
|
90
|
+
end
|
91
|
+
|
92
|
+
def add_to_links(links, prefix, options = {})
|
93
|
+
expected_value = parse_fieldset_value(options)
|
94
|
+
return unless expected_value.present?
|
95
|
+
prefix_name = set_fieldset_key(links, prefix || 'basic_info')
|
96
|
+
links[prefix_name][options[:key]] = expected_value
|
97
|
+
end
|
98
|
+
|
99
|
+
def fieldsets
|
100
|
+
@fieldsets ||= fetch_fieldsets(parse_exception_options).except(:env)
|
101
|
+
end
|
102
|
+
|
103
|
+
def render_template(template = nil)
|
104
|
+
execute_with_rescue do
|
105
|
+
current_template = template.present? ? template : @template_path
|
106
|
+
Tilt.new(current_template).render(self, @template_params.stringify_keys)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def create_tempfile(output = render_template)
|
111
|
+
tempfile = Tempfile.new([SecureRandom.uuid, ".#{@template_details[:template_extension]}"], encoding: 'utf-8')
|
112
|
+
tempfile.write(output)
|
113
|
+
tempfile.close
|
114
|
+
details = tempfile_details(tempfile)
|
115
|
+
[details[:filename], details[:path]]
|
116
|
+
end
|
117
|
+
|
118
|
+
def fetch_archives(output = render_template)
|
119
|
+
return [] if output.blank?
|
120
|
+
filename, path = create_tempfile(output)
|
121
|
+
archive = compress_files(File.dirname(path), filename, [path])
|
122
|
+
remove_tempfile(path)
|
123
|
+
split_archive(archive, "part_#{filename}", 1024 * 1024 * 100)
|
124
|
+
end
|
125
|
+
|
126
|
+
def remove_tempfile(path)
|
127
|
+
if ENV['DEBUG_ASANA_TEMPLATE']
|
128
|
+
logger.debug(path)
|
129
|
+
else
|
130
|
+
FileUtils.rm_rf([path])
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|