Skip to content
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 7 commits into from
Nov 21, 2018
Merged

Global error handler #73

merged 7 commits into from
Nov 21, 2018

Conversation

eguzki
Copy link
Member

@eguzki eguzki commented Nov 9, 2018

Main error handler for all commands

  • print just error when error type is expected or generated in a controlled manner
  • print verbose information when unexpected error happen. In addition to stack trace dump, crash.log is created with app version, system information, installed gems and load paths

@eguzki eguzki requested a review from mikz November 9, 2018 18:25
def error_watchdog(exit_on_error:)
# Set exit handler
%w[INT TERM].each do |signal|
Signal.trap(signal) do
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Signal.trap is global, so I'd rather seen it in the main CLI module.


def write_system_information(stream)
write_section_header(stream, 'System Information')
stream.puts `uname -a`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use Etc.uname for that.

def print_error(error)
write_error(error, $stderr)

File.open('crash.log', 'w') do |io|
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is better to just print it to the STDERR.

For example, in containers, the filesystem can disappear and you are only left with stdout/stderr.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some information like error message and stacktrace is printed to STDERR.

For providing support lots of information bits are dumped to a file. Have seen it in other projects and I think it is a good idea.

If working with ephemeral containers, this feature will be disabled, obviously.

else
print_error(error)
end
exit(1) if exit_on_error
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the better place for this is the main CLI module. This flag is being passed across several methods in the end to just call exit.

puts 'Caught USR1; dumping a stack trace'
puts caller.map { |i| " #{i}" }.join("\n")
end
rescue ArgumentError
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rubocop should scream about this. Why this error can happen? At least a comment explaining why it would be useful.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, Rubocop complaining.

Read about that when some signal cannot be trapped, ArgumentError is raised. The intention was to avoid error propagation and silently lose feature of dumping stack trace on USR1 signal.

Will add a comment

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will remove error catching 👍

@eguzki
Copy link
Member Author

eguzki commented Nov 15, 2018

moved error handling to ThreeScaleToolbox::CLI module

@eguzki eguzki changed the title (WIP) Global error handler Global error handler Nov 16, 2018

def error_watchdog(exit_on_error:)
# Set exit handler
%w[INT TERM].each do |signal|
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still in the ErrorHandler module. It is something that is global and being executed in a block.

By moving it into the main module I did not simply mean move the ErrorHandler module contents to a different file, but move this code into the other module so it is obvious it is global.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

# Catches errors and prints nice diagnostic messages
def error_watchdog(exit_on_error:)
# Set exit handler
%w[INT TERM].each do |signal|
Copy link
Contributor

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 be yield + rescue. Installing signal handlers should be done in self.run before entering the error_watchdog.

else
print_error(error)
end
exit(1) if exit_on_error
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is passing a parameter 3 levels deep just to call exit. IMO this should be done in self.run. That is what I meant by doing it in the CLI module. Not moving the whole method, but just this action.

@eguzki
Copy link
Member Author

eguzki commented Nov 20, 2018

Signal handlers installed by CLI module, error handler logic in its own module and exit done at entrypoint script


# Catches errors and prints nice diagnostic messages
def error_watchdog
error = false
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not?

def error_watchdog
  yield
  false
rescue StandardError, ScriptError => err
  handle_error err
  return err
end

exe/3scale Outdated
@@ -4,4 +4,4 @@ require '3scale_toolbox'

args = ARGV.clone

ThreeScaleToolbox::CLI.run args
exit(ThreeScaleToolbox::CLI.run(args) ? 1 : 0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems a bit odd to signal error with truthy return value.

@eguzki
Copy link
Member Author

eguzki commented Nov 21, 2018

ThreeScaleToolbox::CLI.run computes exit status code

Copy link
Contributor

@mikz mikz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent!

@eguzki eguzki merged commit a5f0c12 into master Nov 21, 2018
@eguzki eguzki deleted the main-error-handler branch November 21, 2018 10:29
@eguzki eguzki mentioned this pull request Mar 13, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants