Протоколирование лучшей информации об исключениях в Java

#java #design-patterns #exception #exception-handling

#java #шаблоны проектирования #исключение

Вопрос:

Я работаю над большим веб-приложением Java с Spring, Hibernate и некоторыми другими библиотеками, включая Apache log4j для ведения журнала. Один из моих текущих проектов — переписать большое количество исключений в устаревших областях (которые я не писал!) кода, Чтобы предоставить более разумную информацию. Типичный блок исключений выглядит следующим образом:

 try {
  //Some Hibernate business here
}
catch (Exception e) {   //Yes, Exception. That's not just me being general. I find this especially frustrating.
  log4j.error("Fail to XXXXXX");   //again, real
  throw new MyException();
}
  

Как вы можете догадаться, это создает некоторые сложные журналы. Я ищу стандартный способ получить лучшую информацию из этих исключений. Большинство из них переносят вызовы гибернации, если это помогает. Вот типичный блок, похожий на тот, который я только что написал:

 try {
    myList.add( ((myClass) commonService.getRecordByTableId(myClass.class, ID)).toString() );
} catch (ServiceException e) {
    log4j.error("Failed to retrieve record from table myClass for id "   ID);
    e.printStackTrace();
}
  

Здесь я извлекаю запись из базы данных и добавляю ее в список. В блоке catch я регистрирую то, что, по моему мнению, является разумным сообщением о том, что try делает блок, и печатаю трассировку стека. Итак, мой вопрос: есть ли что-нибудь еще, что я мог / должен делать, в общем, чтобы получить лучшую информацию для диагностики ошибок?

Ответ №1:

При обработке исключений ведение журнала и повторное выбрасывание является популярным антишаблоном. Вы не должны этого делать. Вам нужно решить, перехватывать ли исключение, затем правильно обрабатывать его (включая ведение журнала) или не перехватывать его и разрешить ему переходить на более высокие уровни (или повторно использовать его / обернуть его в исключение во время выполнения, если это было проверенное исключение).

Если вы это сделаете (log rethrow), то вышестоящий код не сможет узнать, что вы уже зарегистрировали исключение, и поэтому одно и то же исключение может регистрироваться дважды или более, в зависимости от того, через сколько слоев должно пройти исключение, и какой уровень произвольно решает регистрировать иповторно выбросьте его. Это сделает чтение журналов и их устранение полным кошмаром.

Также вы можете утверждать, что выбрасывание и перехват исключений являются дорогостоящими операциями, весь этот перехват и повторное перемещение не способствуют вашей производительности во время выполнения.

Итак, если вы решите фактически обработать исключение, то проглатывать его — неправильный способ (даже если вы регистрируете какое-то сообщение). По крайней мере, вам нужно зарегистрировать трассировку:

 log4j.error("Failed to retrieve record from table myClass for id "   ID, e);
  

Комментарии:

1. 1. Я бы тоже дал больше очков, если бы мог. Я так устал видеть трассировку стека с несколькими «отголосками» перед ней.

2. Да, я тоже. Удивительно, как много «серьезных» разработчиков считают ведение журнала и повторное перемещение достаточно хорошей обработкой для большинства исключений.

3. 1, хороший вызов. Многое из того, что произошло в этом проекте, меня очень огорчает, и я пытаюсь привести это в форму. : D

4. Кроме того, мне нравится слово «анти-шаблон».

Ответ №2:

printStackTrace() не добавляет трассировку в ваш журнал. Отправка исключения в log4j напечатает его в вашем файле журнала, где контекст имеет смысл:

 log4j.error("Failed to retrieve record from table myClass for id "   ID, e);
  

Ответ №3:

Несколько вещей в дополнение к тому, что упоминали другие:

  1. Используйте различные уровни ведения журнала: информация; предупреждение; и т.д.
  2. Следуя # 1, я бы отказался от этих вызовов printStackTrace(). Если вы хотите регистрировать ошибки в консоли, делайте это через регистратор. Таким образом, вы получаете преимущества фильтрации уровней даже для консоли.

Ответ №4:

да, в самом первом блоке это должно быть так:

 try {
  //Some Hibernate business here
}
catch (Exception e) {   //Yes, Exception.  That's not just me being general
  log4j.error("Fail to XXXXXX", e);   //again, real
  throw new MyException(e);
}
  

Java позволяет создавать цепочки исключений, поэтому вы должны это делать. Кроме того, при использовании Log4J вы также можете отправить исключение, чтобы оно также печатало трассировку стека исключений в ваших журналах.