Каковы некоторые шаблоны и анти-шаблоны ведения журнала приложений? [закрыто]


67

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

Примечание: я понимаю, что не все ошибки обнаруживаются через журналы. Это не меняет того факта, что журналы ужасны.

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

Вместо этого, чтобы оценить, насколько плохо мы делаем на фронте регистрации, я хотел бы знать:

  1. Каковы некоторые рекомендации , если таковые имеются, когда дело доходит до регистрации для приложения, особенно большого приложения.
  2. Есть ли какие-то паттерны, которым мы должны следовать, или анти-паттерны, о которых мы должны знать?
  3. Это важная вещь, которую нужно исправить, или это можно исправить, или все файлы журналов просто огромны, и вам нужны дополнительные сценарии для их анализа?

Примечание: мы используем log4j.

Ответы:


56

Несколько моментов, которые моя практика оказалась полезной:

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

  • Сделайте логи удобными для анализа grep. Придерживайтесь нескольких общих полей в начале каждой строки. Определите время, серьезность и подсистему в каждой строке. Четко сформулируйте сообщение. Сделайте так, чтобы каждое сообщение журнала было легко сопоставлено с его строкой исходного кода.

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

Журналы в основном нужны для мониторинга и устранения неполадок. Поставьте себя на место помощника по устранению неполадок и подумайте, какие журналы вы хотели бы иметь, когда что-то происходит не так или происходит в глубокой ночи.


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

4
+1. Мне нравится ваша точка зрения о том, чтобы поставить себя на место неисправного. Звучит так,
словосочетания

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

2
@SnOrfus: Есть несколько способов хранения журналов, но суть в том, что сообщения журналов должны быть доступны до самой последней секунды, когда система рухнула - как черный ящик самолета. Если вы используете какой-либо вид буферизации, предоставьте возможность обойти это / очистить каждое сообщение.
Rwong

1
@Rig: с другой стороны, многие доморощенные регистраторы не реализовали никакой буферизации (и должным образом очищали каждое сообщение), что приводило к очень низкой производительности. Вот почему это должно быть сделано необязательно.
rwong

28

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

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

Я проектирую системы, которые способны регистрировать практически все, но я не включаю все по умолчанию. Отладочная информация отправляется в скрытое диалоговое окно отладки, которое ставит метки времени и выводит его в список (ограниченный до 500 строк перед удалением), и диалоговое окно позволяет мне остановить его, автоматически сохранить в файле журнала или перенаправить в прикрепленный отладчик. Это отвлечение позволяет мне видеть вывод отладки из нескольких приложений, все аккуратно сериализованные, что иногда может быть спасением. Я использовал , чтобы использовать цифровые уровни ведения журнала (чем выше вы установите уровень, тем больше вы захват):

off
errors only
basic
detailed
everything

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

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

#define DEBUG_ERROR          1
#define DEBUG_BASIC          2
#define DEBUG_DETAIL         4
#define DEBUG_MSG_BASIC      8
#define DEBUG_MSG_POLL       16
#define DEBUG_MSG_STATUS     32
#define DEBUG_METRICS        64
#define DEBUG_EXCEPTION      128
#define DEBUG_STATE_CHANGE   256
#define DEBUG_DB_READ        512
#define DEBUG_DB_WRITE       1024
#define DEBUG_SQL_TEXT       2048
#define DEBUG_MSG_CONTENTS   4096

Эта система ведения журнала поставляется с версией сборки, включенной и сохраняемой в файл по умолчанию. Уже слишком поздно выяснять, что вы должны были регистрироваться ПОСЛЕ того, как произошла ошибка, если эта ошибка возникает в среднем раз в шесть месяцев, и у вас нет возможности ее воспроизвести. Ведение журнала, которое работает только с отладочными сборками, просто. равнина. тупой.

Программное обеспечение обычно поставляется с включенными ERROR, BASIC, STATE_CHANGE и EXCEPTION, но это можно изменить в поле через диалоговое окно отладки (или настройки реестра / ini / cfg, где эти вещи сохраняются).

Да, и одно: моя система отладки генерирует один файл в день. Ваши требования могут отличаться. Но убедитесь, что ваш код отладки начинает каждый файл с даты, версии кода, который вы запускаете, и, если возможно, некоторого маркера для идентификатора клиента, местоположения системы или чего-либо еще. Вы можете получить кучу файлов журналов, поступающих с поля, и вам понадобится некоторая запись того, откуда и какая версия системы, на которой они работали, на самом деле в самих данных, и вы не можете доверять клиенту. / Инженер-полевой, чтобы сказать вам, какая у них версия - они могут просто сказать вам, какую версию, по их мнению, они получили. Хуже того, они могут сообщить версию exe, которая находится на диске, но старая версия все еще работает, потому что они забыли перезагрузить компьютер после замены. Пусть ваш код скажет вам сам.

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


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

27

Мой любимый общедоступный ресурс для рекомендаций по ведению журналов - Apache JCL Best Practices .

Лучшие практики для JCL представлены в двух категориях: Общие и Предприятие. Общие принципы довольно ясны. Практика предприятия немного сложнее, и не всегда так ясно, почему они важны.

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

Несмотря на нацеленность на JCL, они кажутся достаточно общими, чтобы их можно было использовать для ведения журнала в целом.

  • Мои личные «правила» ведения журналов таковы, что на уровне отладки я стараюсь, чтобы мои журналы читались как история - с понятной логикой и достаточными (но не перегруженными) деталями.

Самый известный анти-паттерн - это, вероятно, «проглатывание исключений» - просто поищите его в Интернете.

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

  • Выше не означает, однако, что вы должны всегда вслепую складывать все журналы в один огромный файл. Иногда может быть полезно написать / скопировать некоторые журналы в отдельные файлы. Например, в моем недавнем проекте QA ребята попросили специальные файлы для метрик и временных данных, а также для кратких отчетов о работе системы. Они сказали, что получат пользу от этого, и dev сделал это (выгода от файла кратких отчетов оказалась действительно существенной).

PS. Что касается анти-паттернов, то другие, которые приходят на ум, - это «наводнения» и бессмысленные сообщения.

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

  • Бессмысленные сообщения кажутся довольно популярным мусором. Они выглядят безвредными при чтении в исходном коде - я думаю, что нужно пройти через анализ анализа отладочной информации, похожей на ...

    step #1
    step #2
    step #3
    

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


4
Чтобы избежать затопления, я обычно собираю эвристику цикла и выводю ее после цикла. То есть все, что происходит в цикле, должно быть сохранено в переменной (например somethingSpecialHappenedCount), а затем выведено в логгер.
Спойк

@ Спайк, хорошая мысль! хранение в переменной действительно один из моих любимых приемов борьбы с наводнениями
комнат

1
После завершения цикла я вывожу все различные счетчики в журнал в виде ASCII-таблицы в журнале, чтобы их можно было легко сравнить. Идея таблицы была вдохновлена ​​тем, что генерирует Spring StopWatch.prettyPrint () . Помимо этого, сделать текст журнала читабельным и актуальным по-прежнему остается «искусством», как упоминалось ранее в ответе.
Spoike

@Spoike: (и @gnat) Это интересно. Таким образом, в основном вы добавляете реальный код в бизнес-логику только для целей регистрации? Я никогда не слышал об этом и не делал этого раньше и не уверен, как бы я оправдал это перед моими коллегами. Я боюсь, что если мы начнем делать это, некоторые из наших разработчиков будут загромождать исходный код до такой степени, что бизнес-логика станет запутанной и трудной для чтения. Просто регистрация заявления уже делает исходный код более уродливым.
c_maker

2
@c_maker Ваша точка зрения о смешении ведения журнала с бизнес-логикой стоит отдельного вопроса. Лично у меня пока нет твердого мнения по этим вопросам. Теоретически можно представить некоторые улучшения разделения с использованием AOP и iirc, и даже есть практические применения для этого подхода. На практике, однако, я придерживаюсь «смешанного» подхода, и до сих пор у меня не было серьезных проблем с ним. Загромождение исходного кода представляет собой реальную опасность, но, опять же, до сих пор я смог заставить его сосуществовать с регистрационным кодом довольно «мирно». Это, конечно, требует определенных усилий.
комнат

11

Зарегистрируйте исключение только один раз!

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


5

Вот антишаблон: создание двух дюжин «общих переменных» полей в таблице базы данных для отслеживания чего-либо мыслимого, а затем получение 88 (и подсчет) различных значений перечисления для разных типов журналов.


+1 - я видел это. «Таблицы ошибок», в которых есть такие столбцы, как строка1, строка2, строка3, строка4, строка5, где объединение всех столбцов приведет к коду ошибки, на который нет ссылок ни в одной документации. Результатом является регистрация, которая является одновременно запутанной и бесполезной; также известный как "стороннее предприятие-приложение-приложение-с-разработкой-отладкой-адом".
Морган Херлокер

В моем случае это «система регистрации вручную, без какого-либо представления о том, что на самом деле включает регистрация»,
Уэйн Молина,

4

Мой опыт работы с журналами - чем больше, тем лучше, но он должен быть достаточно последовательным, чтобы его можно было фильтровать на машине, и иметь возможность настраивать уровень серьезности для каждого компонента вашего приложения в отдельности.

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


2

Пару заметок с оперативной стороны дома здесь:

1) Убедитесь, что журналы настраиваются локально, желательно с помощью инструмента, не более тяжелого, чем текстовый редактор. Большую часть времени мы не хотим регистрировать уровень TRACE, но нам нравится включать его.

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


1

Из собственного опыта работы с веб-приложениями:

(и учитывая, что хранение сейчас очень дешево)

  • Записывайте как можно больше доступной (в данный момент) информации.
  • Я всегда включаю DateTime.Now в мои строки журнала.
  • Я всегда (если это возможно) записываю время-продолжительность какого-то конкретного «действия».
  • Будьте последовательны с вашими лог-строками. Так как я всегда использую этот тип шаблона:

    • «[Info X] [Info Y] [Info Z] [и т. Д.]»

1

Помимо трассировки стека, запишите текущее состояние приложения и входные данные.

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

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


3
«Программное обеспечение детерминировано» => к сожалению, не всегда. Подумайте, например, об ошибках параллелизма.
assylias
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.