Как правильно обрабатывать журналы ошибок? - PullRequest
1 голос
/ 06 марта 2009

Я пытался сделать несколько поисков, прежде чем опубликовать этот вопрос. Если это дубликат, сообщите мне, и я его удалю.

Мой вопрос вращается вокруг правильного способа обработки ошибок, вызванных нашим веб-приложением. В настоящее время мы регистрируем все через log4j. Если возникает ошибка, она просто говорит: «Произошла ошибка. ИТ-отдел был уведомлен и постарается исправить это как можно скорее» прямо на экране. Это ничего не говорит пользователю ... но также ничего не говорит разработчику, когда мы пытаемся воспроизвести ошибку. Мы должны перейти в папку журнала ошибок и попытаться найти эту ошибку. Позвольте мне также упомянуть, что папка полна журналов с прошлой недели. Каждый раз, когда возникает ошибка, для этого пользователя создается один файл журнала, и электронное письмо отправляется ИТ-персоналу, назначенному для работы с ошибками. В этом письме не упоминается имя файла журнала, но это копия того же текста ошибки, который был записан в файле журнала.

Так что, если у Алисии есть проблема в 7:15 с чем-то, но в ту же минуту происходит еще 10 ошибок, я должен просмотреть каждый файл журнала, пытаясь найти ее.

То, что я предлагал своим коллегам по работе, - это добавление таблицы журнала ошибок в базу данных. Это будет записывать запись в таблицу для каждой ошибки, записи, для которой она предназначена, ошибки, на какой странице она произошла и т. Д. Бонусом этого будет то, что мы можем вернуть значение первичного ключа из таблицы (error_log_id) и покажите, что на странице с сообщением типа «Идентификатор ошибки (1337) был зарегистрирован и соответствующий ИТ-персонал был уведомлен. Пожалуйста, держите этот ссылочный идентификатор под рукой для будущего использования». Когда мы получим электронное письмо, в нем будет указан идентификатор ошибки для быстрого ознакомления. Или, если пользователь постоянный, он может связаться с нами с помощью идентификатора, и мы довольно быстро найдем ошибку.

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

Ответы [ 6 ]

5 голосов
/ 06 марта 2009

Я ответил на аналогичный вопрос здесь , но я адаптирую этот ответ к вашему вопросу.

Мы используем requestID для этой цели - присваиваем идентификатор запроса каждому входящему (HTTP) запросу в самом начале обработки (в фильтре), а затем регистрируем его в каждой строке журнала, чтобы вы могли легко сгенерируйте эти журналы позже по этому идентификатору и найдите все соответствующие строки.

Если вы считаете, что добавлять этот идентификатор в каждый оператор журнала очень утомительно, значит, вы не одиноки - рамки ведения журналов Java сделали его прозрачным с помощью Mapped Diagnostic Context (MDC) (в по крайней мере log4j и logback имеют это).

RequestID может также работать как удобный ссылочный номер, чтобы выкладываться в случае ошибок (как вы уже предлагали). Однако, как прокомментировали другие, не стоит загружать эти данные в базу данных - лучше использовать файловую систему. Или самый простой подход - просто использовать requestID - тогда вам не нужно делать ничего особенного в момент возникновения ошибки. Это просто поможет вам найти правильный файл журнала и выполнить поиск внутри этого файла.

Как будет выглядеть один requestID?

Мы используем следующую схему:

:. 1022 *

In состоит из следующих переменных:

  • instanceName уникально идентифицирует конкретную JVM в конкретной среде развертывания /.
  • currentTimeInMillis не требует пояснений. Мы решили представить его в удобочитаемом формате «yyyyMMddHHmmssSSS», поэтому из него легко прочитать время начала запроса (будьте осторожны: SimpleDateFormat не является потокобезопасным, поэтому вам нужно либо синхронизировать его, либо создавать новый при каждом запросе). ).
  • counter - это счетчик запросов в эту конкретную миллисекунду - в редких случаях вам может потребоваться сгенерировать более одного идентификатора запроса за одну миллисекунду

Как видите, формат идентификатора был настроен таким образом, что комбинация currentTimeInMillis.counter гарантированно уникальна в конкретной JVM, а весь идентификатор гарантированно будет глобально уникальным (хорошо не в истинном смысле «глобальный», но он достаточно глобален для наших целей), без необходимости задействовать базу данных или какой-либо другой центральный узел. Кроме того, использование переменной instanceName дает вам возможность ограничить количество файлов журналов, которые вам позже понадобятся для поиска этого запроса.

Тогда, последний вопрос: «это хорошо и просто в решении с одной JVM, но как вы масштабируете это для нескольких JVM, взаимодействующих по некоторому сетевому протоколу?»

Поскольку мы используем Spring Remoting для целей удаленного взаимодействия, мы реализовали пользовательскую RemoteInvocationFactory (которая берет идентификатор запроса из контекста и сохраняет его в Атрибуты RemoteInvocation ) и RemoteInvocationExecutor (который берет идентификатор запроса из атрибутов и добавляет его в контекст диагностики в другой JVM).

Не уверен, как бы вы реализовали это с обычным RMI или другими методами удаленного взаимодействия.

1 голос
/ 06 марта 2009

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

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

В разработанном нами дизайне трассы равных стеков принадлежат одним и тем же записям (поскольку они были созданы в одном и том же месте)

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

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

Со временем системные администраторы узнают, что делать с каждым типом исключения, и действуют соответствующим образом.

Но! Ваше приложение может быть не таким уж большим. Вероятно, вы можете иметь то же самое, просто анализируя файлы журналов.

1 голос
/ 06 марта 2009

Для стратегий ведения журнала вы можете увидеть обсуждение Лучшие методы ведения журнала .

1 голос
/ 06 марта 2009

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

---- Пожалуйста, не изменяйте информацию ниже этой строки .---

Сведения об ошибке

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

На самом деле я считаю полезным печатать подробности об ошибках в HTML-комментариях на таких страницах ошибок, чтобы я всегда мог их найти.

Я согласен с Дэвидом выше, что мне не нравится хранить такую ​​информацию в БД.

1 голос
/ 06 марта 2009

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

1 голос
/ 06 марта 2009

Я бы выступил против идеи хранения журналов ошибок в базе данных. Система ведения журнала должна быть максимально простой и не включать компоненты, которые не на 100% необходимы для записи записи журнала.

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

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

В проектах, к которым я причастен, общее руководство заключается в том, чтобы регистрировать ошибки как можно более подробно и включать как можно больше контекстной информации (для записи журналов мы обычно используем «обычный» подход - log4j или simillar ). Обычно это хорошо работает даже для сильно нагруженных систем.

...