Исключение Ruby reraising w/дополнительный аргумент строки

Вот ситуация. Я хочу, чтобы все исключения в doStuff() выливались через код, чтобы они обрабатывались на более высоком уровне.

Я также хотел бы записать, как часто любые исключения выполняются в doStuff() на более высоком уровне, и я в настоящее время делаю это:

begin
  doStuff()
rescue Exception =>
  raise e, "specific error to log in a db"

Код doStuff генерирует десятки исключений, и я хочу зафиксировать каждое из этих событий, чтобы положить в db. Существует doStuff2(), который также может передавать идентичные инструкции, и я хочу знать, из какой функции они пришли.

Добавление дополнительной строки, кажется, изменяет само исключение, и я теряю все хорошие данные о форматировании и трассировке, которые были в исходном исключении.

Любые предложения о том, как я могу сделать ререйз оригинального исключения, но также отслеживать все исключения, которые происходят в doStuff()?

Ответы

Ответ 1

Если вы вызываете raise без передачи какого-либо аргумента, Ruby будет повторно поднимать последнее исключение.

begin
  doStuff()
rescue => e
  log_exception(e)
  raise  # This will re-raise the last exception.
end

В качестве дополнительной заметки я хотел бы рассказать вам о лучших практиках Ruby.

  • doStuff() метод не соответствует соглашениям об именах Ruby. Вы должны использовать подчеркивание для методов. Используйте do_stuff. Кроме того, нет необходимости использовать (), если нет аргументов.
  • Никогда не спасайте Exception, вместо этого спасайте самый низкоуровневый класс, который вам нужно спасти. В большинстве случаев вам может понадобиться спасти все типы StandardError или RuntimeError. Фактически, если вы используете спасение без передачи типа ошибки, Ruby автоматически спасет любой подкласс StandardError. Exception класс очень низкий, и он также будет улавливать синтаксические ошибки и несколько других проблем компилятора. Возможно, вы захотите, чтобы приложение вышло из строя в этом случае, чтобы вы не развертывали сломанное приложение.

Ответ 2

Вы можете сохранить обратную трассировку и сообщение первого исключения и создать новое исключение для повышения

begin
rescue Exception => e 
  new_ex = Exception.new("Error while executing ...:#{e.message}")
  new_ex.set_backtrace(e.backtrace)
  raise new_ex
end

Ответ 3

Вы не можете создать новое исключение и сохранить предыдущее исключение и его стек из таблицы. Вложенные исключения из Java-мира, к сожалению, недоступны. Он будет доступен в Ruby 2.1. Это довольно горячая тема. https://bugs.ruby-lang.org/issues/8257

Вы можете использовать nesty gem для его использования. Вам нужно только include Nesty::NestedError в ваших классах исключений. Больше информации здесь: https://github.com/skorks/nesty/