-
Notifications
You must be signed in to change notification settings - Fork 73
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Global error handler #73
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
9202e26
global error handler
eguzki 4d7a0a4
3scale_toolbox/cli: error handling in CLI module
eguzki e920ab9
3scale_toolbox/cli: bash error color formatting
eguzki 8fe689d
error_handler_spec: error handler class tests
eguzki f545388
error handling is global at CLI module
eguzki 7a999ff
signal handlers installed by CLI and exit only at highest level
eguzki 3784ac1
error handler returns error to compute process exit code
eguzki File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,4 +4,4 @@ require '3scale_toolbox' | |
|
||
args = ARGV.clone | ||
|
||
ThreeScaleToolbox::CLI.run args | ||
exit(ThreeScaleToolbox::CLI.run(args)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
require 'json' | ||
|
||
module ThreeScaleToolbox | ||
module CLI | ||
class ErrorHandler | ||
def self.error_watchdog | ||
new.error_watchdog { yield } | ||
end | ||
|
||
# Catches errors and prints nice diagnostic messages | ||
def error_watchdog | ||
# Run | ||
yield | ||
rescue StandardError, ScriptError => e | ||
handle_error e | ||
e | ||
else | ||
nil | ||
end | ||
|
||
private | ||
|
||
def handle_error(error) | ||
if expected_error?(error) | ||
warn | ||
warn "\e[1m\e[31mError: #{error.message}\e[0m" | ||
else | ||
print_error(error) | ||
end | ||
end | ||
|
||
def expected_error?(error) | ||
case error | ||
when ThreeScaleToolbox::Error | ||
true | ||
else | ||
false | ||
end | ||
end | ||
|
||
def print_error(error) | ||
write_error(error, $stderr) | ||
|
||
File.open('crash.log', 'w') do |io| | ||
write_verbose_error(error, io) | ||
end | ||
|
||
write_section_header($stderr, 'Detailed information') | ||
warn | ||
warn 'A detailed crash log has been written to ./crash.log.' | ||
end | ||
|
||
def write_error(error, stream) | ||
write_error_message(error, stream) | ||
write_stack_trace(error, stream) | ||
end | ||
|
||
def write_error_message(error, stream) | ||
write_section_header(stream, 'Message') | ||
stream.puts "\e[1m\e[31m#{error.class}: #{error.message}\e[0m" | ||
end | ||
|
||
def write_stack_trace(error, stream) | ||
write_section_header(stream, 'Backtrace') | ||
stream.puts error.backtrace | ||
end | ||
|
||
def write_version_information(stream) | ||
write_section_header(stream, 'Version Information') | ||
stream.puts ThreeScaleToolbox::VERSION | ||
end | ||
|
||
def write_system_information(stream) | ||
write_section_header(stream, 'System Information') | ||
stream.puts Etc.uname.to_json | ||
end | ||
|
||
def write_installed_gems(stream) | ||
write_section_header(stream, 'Installed gems') | ||
gems_and_versions.each do |g| | ||
stream.puts " #{g.first} #{g.last.join(', ')}" | ||
end | ||
end | ||
|
||
def write_load_paths(stream) | ||
write_section_header(stream, 'Load paths') | ||
$LOAD_PATH.each_with_index do |i, index| | ||
stream.puts " #{index}. #{i}" | ||
end | ||
end | ||
|
||
def write_verbose_error(error, stream) | ||
stream.puts "Crashlog created at #{Time.now}" | ||
|
||
write_error_message(error, stream) | ||
write_stack_trace(error, stream) | ||
write_version_information(stream) | ||
write_system_information(stream) | ||
write_installed_gems(stream) | ||
write_load_paths(stream) | ||
end | ||
|
||
def gems_and_versions | ||
gems = {} | ||
Gem::Specification.find_all.sort_by { |s| [s.name, s.version] }.each do |spec| | ||
gems[spec.name] ||= [] | ||
gems[spec.name] << spec.version.to_s | ||
end | ||
gems | ||
end | ||
|
||
def write_section_header(stream, title) | ||
stream.puts | ||
|
||
stream.puts "===== #{title.upcase}:" | ||
stream.puts | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
require '3scale_toolbox' | ||
|
||
RSpec.describe ThreeScaleToolbox::CLI::ErrorHandler do | ||
include_context :temp_dir | ||
|
||
context '#error_watchdog' do | ||
def raise_runtime_error | ||
raise 'some error' | ||
end | ||
|
||
def raise_toolbox_error | ||
raise ThreeScaleToolbox::Error, 'some error' | ||
end | ||
|
||
context 'raises expected error' do | ||
it 'error is shown on stderr' do | ||
Dir.chdir(tmp_dir) do | ||
expect do | ||
subject.error_watchdog { raise_toolbox_error } | ||
end.to output(/some error/).to_stderr | ||
expect(File).not_to exist('crash.log') | ||
end | ||
end | ||
|
||
it 'returns error' do | ||
expect( | ||
subject.error_watchdog { raise_toolbox_error } | ||
).to be | ||
end | ||
end | ||
|
||
context 'raises unexpected error' do | ||
it 'crash.log is generated' do | ||
Dir.chdir(tmp_dir) do | ||
expect do | ||
subject.error_watchdog { raise_runtime_error } | ||
end.to output(/some error/).to_stderr | ||
expect(File).to exist('crash.log') | ||
end | ||
end | ||
|
||
it 'returns error' do | ||
expect( | ||
subject.error_watchdog { raise_runtime_error } | ||
).to be | ||
end | ||
end | ||
|
||
context 'Does not raise error' do | ||
it 'returns true' do | ||
expect(subject.error_watchdog {}).to be_nil | ||
end | ||
end | ||
end | ||
end |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is just moving this from one module from another. It does not address the fact that this is global action that is for example not reverted back.
IMO this class does not have one reason to change. It does error handling but also installs signal handlers for an interruption. Those are two different concepts that should be separate.
error_watchdog
should basically just beyield
+rescue
. Installing signal handlers should be done inself.run
before entering theerror_watchdog
.