Представьте, если хотите, вы работаете над новым критическим приложением, и вам нужно записать результаты вычислений процесса в файл. Простые вещи, несколько строк Java позже у вас есть …
File file = new File("myfile.txt"); try { boolean fileCreated = file.createNewFile(); log.debug("fileCreated = " + fileCreated); } catch (IOException e) { log.error("Could not create file",e); }
Вы даже не забыли записать исключение в журналы на случай, если в работе возникла проблема. Несколько недель спустя код поставляется и отлично работает в течение нескольких недель, пока однажды не исчезнет монтирование сети и приложение не начнет выдавать исключения.
Журналы ваших приложений затем заполняются сообщениями об исключениях и трассировкой стека, но никто не понимает, что существует проблема, пока не разозлится рассерженный клиент с жалобой на то, что он так и не получил свой отчет.
Гораздо худший сценарий состоит в том, что исключение возникает в производственном процессе, но сотрудники по разработке решают, что это «хорошее исключение» и что наилучший способ действий — игнорировать его. Навсегда! Ну, пока новый парень не начинает, и они должны объяснить, что это «хорошее исключение», и следующие 600 исключений.
Я помню, когда я впервые услышал термин «Хорошее исключение», я работал на стартап в Лондоне более десяти лет назад. Я был новичком в компании, и первая фаза приложения уже была в производстве как часть критической бета-фазы продукта. Каждое утро разработчик должен быть в офисе и иметь дело с любыми проблемами, которые могут возникнуть с 6 утра.
В одно холодное декабрьское утро я был в офисе и, как часть утренней рутины, проходил проверку заявки. Контрольная точка № 27 была «Проверять журналы приложений». Никаких подробностей, поэтому я вскочил на сервер приложений и начал составлять журналы, и, к моему ужасу, сотни исключений регистрировались в реальном времени.
Я потратил следующий час, пытаясь выяснить, что не так с приложением и что изменилось, чтобы вызвать такой шторм исключений на производстве. Около 8:00 один из разработчиков, у которого был самый долгий срок пребывания в команде, пришел и спокойно сказал: «О, это хорошие исключения, вы можете их игнорировать. Они происходят на следующий день после выставления счетов из-за ошибки в одном из основных компонентов ».
Ключевой урок; Исключения должны быть исключительными, если вы получаете исключение в производстве, вам нужно иметь дело с ним.
Исключительный рабочий процесс
Исключения являются частью процесса разработки и мониторинга приложений. В идеале, когда генерируется предупреждение в процессе производства, оно возвращается в процесс разработки в качестве возможного исправления или улучшения. Главное — обеспечить адекватный мониторинг исключений в производстве и обеспечить достаточную обратную связь с командой разработчиков.
Сколько приложений, над которыми вы работали, имели что-то большее, чем уровень журналирования или мониторинг исключений из журнала?
Сколько процессов разработки вы видели, чтобы связать исключение производства с исправлением ошибок и пытаться исправить как можно больше исключений?
Сколько «хороших исключений» было записано в ваши журналы в производстве с тех пор, как вы начали читать этот пост?
Мониторинг выпечки
Лично я думаю, что одной из причин плохой инфраструктуры в критических областях, таких как это, является то, как различные части организации структурированы. Во многих больших командах люди посвящены различным функциям жизненного цикла приложения. Разработчики, как правило, ориентированы на бизнес-требования приложений и имеют неумолимые сроки. У команд поддержки есть сроки другого типа. Они также имеют тенденцию поддерживать множество приложений в широком спектре функций.
С развитием движения DevOps эти сообщества начинают объединять усилия и работать над инфраструктурой, стоящей за приложениями. Таким образом, одна проблема, безусловно, решается и начнет приобретать все большее распространение в ближайшие 2-3 года. Другим важным фактором является поддержка инструментов. Сколько хороших современных инструментов доступно для мониторинга приложений, которые быстро используются и находятся на борту? На данный момент в этом пространстве есть ряд интересных коммерческих стартапов, например , AirBrake используется рядом корпораций для добавления поддержки мониторинга в их приложения.
Airbrake предлагает богатую функциональность, но также поддерживает практически все популярные языки в своем арсенале API. Однако он размещен на их серверах, и такая конфигурация развертывания не подойдет большинству разработчиков приложений, которые разрабатывают программное обеспечение на заказ для внутренних клиентов, и им запрещено публиковать внешнюю информацию независимо от содержимого. Интересно, что существует альтернатива AirBrake с открытым исходным кодом, называемая ErrBit, которая совместима с API AirBrake.
Это приложение ruby on rails, которое может быть легко установлено на вашем локальном сервере, или для целей этого блога я разместил его на Heroku в основном для простоты использования. После того, как вы установили ErrBit, вы можете быстро публиковать исключения и трассировки стека на сервере, и у вас есть некоторый базовый рабочий процесс, чтобы ваши сотрудники службы поддержки могли отслеживать и обрабатывать исключения. Он также интегрирован с некоторыми из самых популярных систем отслеживания ошибок, однако в настоящее время поддержка Jira отсутствует.
Установка ErrBit
Это был первый раз, когда я использовал Heroku для чего-либо, хотя я слышал замечательные вещи. У меня была учетная запись, но это было непроверенное, что я просмотрел, когда я сделал свою первую установку. ErrBit нужен MongoDB, и чтобы использовать MongoDB с Heroku, вам необходимо подтвердить свою учетную запись кредитной картой. Это неожиданно остановило мое приложение на некоторое время, и мне потребовалось много времени, чтобы заметить небольшое сообщение об ошибке в скрипте установки. Вы были предупреждены!
Чтобы установить приложение, вам нужно выполнить простые шаги со страницы github https://github.com/errbit/errbit (вам нужно установить git и ruby локально)
Клонировать хранилище
git clone http://github.com/errbit/errbit.git
Создать и настроить для Heroku
gem install heroku heroku create example-errbit --stack cedar heroku addons:add mongolab:starter cp -f config/mongoid.mongolab.yml config/mongoid.yml git add -f config/mongoid.yml git commit -m "Added mongoid config for Mongolab" heroku addons:add sendgrid:starter heroku config:add HEROKU=true heroku config:add ERRBIT_HOST=some-hostname.example.com heroku config:add [email protected] git push heroku master
Семя БД
heroku run rake db:seed
Довольно быстро, хорошо, когда у вас есть подтвержденный аккаунт Heroku. После завершения просто введите
heroku open
И ваша новая установка ErrBit должна быть запущена. Мой экземпляр находится на ebit.herokuapp.com, и вы можете использовать [email protected]/password для входа
После того, как вы установили ErrBit, вам нужно будет настроить своих пользователей и любые приложения, которые вы планируете отслеживать. Опять же, просто нажав кнопку «Добавить новое приложение», вы попадете на экран конфигурации. Как только вы создадите запись приложения, вы получите важный идентификатор приложения. Он понадобится вам позже при публикации исключений.
Публикация исключений из Java
Как я упоминал ранее, ErrBit совместим со всеми языковыми API, которые предоставляет AirBrake, и, к счастью для меня, существует активно разработанный API для Java, доступный по адресу http://github.com/airbrake/airbrake-java . Это позволит вам отправлять исключения из приложений Java Server, мобильных приложений и настольных клиентов. Чтобы начать использовать его с maven, добавьте следующие зависимости в ваш файл pom
<project> <dependencies> <dependency> <groupId>io.airbrake</groupId> <artifactId>airbrake-java</artifactId> <version>2.2.0</version> </dependency> </dependencies> </project>
После того, как я импортировал библиотеки, я увидел небольшую проблему в том, как переопределить URL для связи с внутренним сервером. В классе AirBrakeNotifier, который отвечает за вызов api rest на стороне сервера, URL для AirBrake жестко закодирован, тогда как мне нужно было переопределить его для ErrBit. Быстрое решение состояло в том, чтобы создать новый класс ErrBitNotifier, который принимает базовый URL как аргумент конструкции.
import airbrake.AirbrakeNotice; import airbrake.NoticeXml; import java.io.*; import java.net.*; public class ErrBitNotifier { private final String baseUrl; public ErrBitNotifier(String baseUrl) { this.baseUrl = baseUrl; } private void addingProperties(final HttpURLConnection connection) throws ProtocolException { connection.setDoOutput(true); connection.setRequestProperty("Content-type", "text/xml"); connection.setRequestProperty("Accept", "text/xml, application/xml"); connection.setRequestMethod("POST"); } private HttpURLConnection createConnection() throws IOException { return (HttpURLConnection) new URL(String.format("http://%s/notifier_api/v2/notices", baseUrl)).openConnection(); } private void err(final AirbrakeNotice notice, final Exception e) { e.printStackTrace(); } public int notify(final AirbrakeNotice notice) { try { final HttpURLConnection toairbrake = createConnection(); addingProperties(toairbrake); String toPost = new NoticeXml(notice).toString(); return send(toPost, toairbrake); } catch (final Exception e) { err(notice, e); } return 0; } private int send(final String yaml, final HttpURLConnection connection) throws IOException { int statusCode; final OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream()); writer.write(yaml); writer.close(); statusCode = connection.getResponseCode(); return statusCode; } }
Возможно, API AirBrake потенциально может позволить настраивать URL в следующей версии. Создав новый ErrBitNotifier, вы можете начать публиковать исключения. Возвращаясь к нашему предыдущему примеру
import airbrake.AirbrakeNotice; import airbrake.AirbrakeNoticeBuilder; import org.apache.log4j.Logger; import java.io.File; import java.io.IOException; public class TestException { private static org.apache.log4j.Logger log = Logger .getLogger(TestException.class); public static void main(String[] args) { File file = new File("h://myfile.txt"); try { boolean fileCreated = file.createNewFile(); System.out.println("fileCreated = " + fileCreated); } catch (IOException e) { log.error("Could not create file",e); AirbrakeNotice notice = new AirbrakeNoticeBuilder("b4f7cb2020b2972bde2f21788105d645", e, "prod").newNotice(); ErrBitNotifier notifier = new ErrBitNotifier("ebit.herokuapp.com"); notifier.notify(notice); } } }
Этот код генерирует IOException (по крайней мере, на моем компьютере, так как у меня нет диска!), И исключение будет отображаться на консоли ErrBit. Он имеет возможность обнаруживать дублирование исключений, и вы можете установить его на напишите вам, когда возникнет исключение.
Также API-интерфейс AirBrake имеет поддержку app4 log4j, но он привязан к общедоступному URL-адресу AirBrake, и я оставил его вне поста. Однако его можно включить в следующем примере конфигурации log4j.
log4j.rootLogger=INFO, stdout, airbrake log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=[%d,%p] [%c{1}.%M:%L] %m%n log4j.appender.airbrake=airbrake.AirbrakeAppender log4j.appender.airbrake.api_key=YOUR_AIRBRAKE_API_KEY #log4j.appender.airbrake.env=development #log4j.appender.airbrake.env=production log4j.appender.airbrake.env=test log4j.appender.airbrake.enabled=true
Вывод
Мониторинг исключений приложений является важной частью жизненного цикла вашего приложения.
Исключения должны быть легко видны командам поддержки и разработки, а ваш процесс разработки должен учитывать все исключения в предстоящих спринтах.
Исключения следует использовать только для исключительных случаев, любое исключение, которое не применяется в производстве, является шумом и создает путаницу.
Поддержка инструментов важна в этой области, и ErrBit выглядит как отличный многоязычный инструмент, который может помочь поддержать ваш рабочий процесс Exception Management.