- PVSM.RU - https://www.pvsm.ru -
В данной статье я хочу поделиться своими мыслями/наблюдениями/рекомендациями относительно реализации такой важной задачи при разработке ПО как протоколирование. В Интернете существует множество статей описывающих инструменты для протоколирования, но очень мало информации о том, какие именно события, и какую информацию, нужно записывать в протокол работы программы.
Очень часто возникает проблема диагностики дефектов в тестовой или рабочей среде, где нет инструментов разработки и отладки. И единственным способом понять, в чем ошибка – добавление строк кода с отладочной информацией и повторная установка приложения, если такие строки не были добавлены ранее. А можно ли сразу писать код так, чтобы информации, которую протоколирует приложение, было бы достаточно для диагностики проблемы?
В статье я совсем не буду касаться таких вопросов как инструменты для протоколирования. Но в любом случае, нужно понимать, что такие инструменты существуют и позволяют фильтровать записываемые в протокол данные и настраивать запись протокола в различные источники.
Основная задача статьи – дать представление разработчикам, какими способами проводится протоколирование, и дать рекомендации о том, где в программе вставлять строчки кода для протоколирования. В этой статье, в основном, будем говорить о трассировке.
Я рассматриваю протоколирование намного шире, чем просто запись в лог-файл. Для меня протоколирование — это набор средств и методов, которые решают такие задачи:
Вышеуказанные цели можно конкретизировать, выделив «пользователей» результатов протоколирования, и задачи этих «пользователей». Далее можно выделить средства и методы, с помощью которых эти задачи можно реализовать. Итак, я вижу 4 основных категории «пользователей»:
В таблице ниже для типов пользователей приведены наиболее часто используемые ими в работе методы и средства для решения своих задач.
| Аудитория | Задача | Средства и методы |
| Разработчик |
|
|
| Тест инженер |
|
|
| Системный администратор |
|
|
| Владелец приложения |
|
|
Указанные в таблице средства и методы кратко описаны ниже.
Выбор и реализация методов протоколирования — очень важная задача, от реализации которой зависит скорость и качество обнаружения и исправления дефектов и качества сопровождения. Поэтому на стадии планирования и разработки этой задаче нужно уделить досрочно внимания и подобрать достаточный набор методов протоколирования.

* картинка взята из статьи Lazy logger levels [1]
Задача трассировки – быстро найти дефект в работе приложения в любой среде (среде разработчика, среде тестирования, рабочей среде) путем анализа работы каждого шага программы. Поэтому логично вносить в трассирующий лог информацию:
Трассировочная информация предназначена главным образом для разработчика и тест инженера (или в рабочей среде — для сотрудников службы сопровождения очень высокого уровня квалификации).
Особенность трассировки заключается в том, что обычно этот функционал не описывается в требованиях, и поэтому разработчикам в начале проекта обычно сложно представить какая трассирующая информация может понадобиться, и, поэтому, сложно понять, что и когда нужно записывать.
Самое главное — понять, что трассировка в рабочей среде включается только при необходимости, т.е. не засоряет журнал событий. Для среды разработчика и среды тестирования трассировка чаще всего включена постоянно для наблюдения за правильностью работы приложения и отладки.
Инструменты для протоколирования обычно дают возможность вести запись в журнал, указывать, куда именно эта информация будет записываться. Важным элементом является также возможность в конфигурации указывать, какие записи попадут в журнал, а какие — нет (обычно это делается на основе категорий событий и уровней событий).
Однако большой проблемой является то, что, несмотря на наличие инструментов редко можно встретить рекомендации как их правильно использовать, а именно:
Это и будет рассмотрено далее в статье.
Важным фактором при выборе событий, которые нужно писать в трассировочный лог зависит, на мой взгляд, от двух факторов:
| Тип приложения | Особенности протоколирования |
| Изолированное desktop приложение (даже не сохраняет ничего на диск) | Если такое приложение хорошо протестировано модульными тестами, то трассировку делать не имеет смысла |
| Приложение для внесения данных и получения отчетов | Тут уже имеется взаимодействие между приложением и хранилищем, и поэтому рационально протоколировать информацию о таком взаимодействии: запросы, количество внесенных и полученных записей, скорость обработки запросов, ключевые параметры для формирования отчетов |
| Инсталлятор приложения (исправления, обновления ) | В данном случае программа тесно взаимодействует с внешней системой и поэтому каждый шаг (попытка выполнить и результат выполнения) должны вносится в трассировочный лог |
| Интеграционная шина | Краткая или полная (полностью данные) информация о поступающих или отправляемых данных |
| Приложение, которое может быть сильно изменено пользователем (или расширено дополнительными модулями и плагинами) | Все взаимодействия с такими внешними модулями (входные/выходные параметры) и влияние установленных параметров конфигурации на работу программы |
Кроме простого названия (описания) события, для анализа работы часто нужна еще дополнительная информация. Следующая таблица показывает данные, которые полезно было бы записывать. Понятно, что далеко не всегда нужно писать события настолько подробно. Кроме того, обычно инструменты трассировки позволяют некоторую из указанной ниже информации записывать автоматически.
| Данные | Описание |
| Дата и время | Дата и время возникновения события |
| Сервер | Сервер, на котором событие возникло (полезно при анализе журналов, собранных с различных серверов) |
| Процесс | Название процесса, где возникло событие. Это необходимо, например, в случае если разные процессы используют общие библиотеки. |
| Метод | Название метода, возможно, включающий название класса и библиотеки |
| Категория события | Название слоя или логического модуля |
| Уровень | Уровень детализации события |
| Название | Название события (запуск или завершение метода, ошибка, изменение состояние объекта и прочее) |
| Детальная информация | Например, детальная информация об ошибке (а при критической ошибке может быть и детальная информация о системе), значение параметра(-ов), название объекта или описание действия над объектом |
| Учетная запись, под которой работает процесс | |
| Учетная запись пользователя, который вызвал действие | Учетная запись пользователя, который сделал начальный вызов, что привело к данному событию |
| Стек | Стек вызовов методов, которая привела к данному событию. Может быть полезен при детальном анализе события |
| Корреляционный номер процесса | Если приложение многопользовательское, то важно понимать к какому запросу (пользователю) относится та или иная запись о события |
| Корреляционный номер инициирующего процесса | Если приложение распределенное, то данный номер используется для сопоставления событий на разных серверах (или процессах). Например, можно передавать с клиента на сервер корреляционный номер и сохранять его при трассировке. В дальнейшем можно сопоставлять вызов клиентского приложения с событием на сервере |
Уровни в основном используются для фильтрации событий при записи в журнал. Это нужно для предотвращения записи в журнал данных, которые в данный период времени не нужны.
Например, такой инструмент как NLog, предоставляет по умолчанию 6 уровней событий (от более детального до менее детального): trace, debug, info, warn, error, fatal (более детально см. в документации к NLog [2])
Далее, в конфигурации можно указать, что, например, в рабочей среде, в журнал трассировки писать события уровня Error и Fatal (а все остальные игнорировать), а при возникновении проблемы изменить конфигурацию так, чтобы записывать все события.
Следующая таблица показывает мои рекомендации по выбору уровней событий при трассировке
| Событие | Уровень |
| Загруженная конфигурация / смена конфигурации | Info |
| Действия пользователя | Info |
| Начало и окончание каждого «публичного» метода (или метода, который реализует логику согласно спецификации), входные/выходные параметры, результат работы такого метода | Info |
| В публичных методах входные/выходные параметры, которые являются наборами данных | Debug |
| Логика (ветки программы) описанная спецификацией | Info |
| Начало и окончание остальных методов, входные/выходные параметры, результат работы | Trace |
| Шаги остальных методов | Trace |
| Доступ к внешним ресурсам (например: БД, web-сервисы) | Info |
| Детальная информация о запросах (командах) доступа к внешним ресурсам и полученном результате | Debug |
| Неожиданные исключения (не критические) | Error |
| Исключение, описанное в спецификации | Warn/Error |
| Обработанные исключения | Warn/Info/ Debug |
| Критическое исключение (обработанное или не обработанное) | Fatal |
Второй важный параметр, по которому можно настроить фильтрацию записи событий в журнал — это категории событий. Эти категории разработчик должен выбирать сам (т.е. инструменты не предоставляют категории по умолчанию)
Я рекомендую придерживаться таких рекомендаций — для каждого отдельного логического уровня сделать отдельную категорию. Например: уровень интерфейса (UIControls), уровень бизнес-логики (BusinessLogic), уровень доступа к данным (DAL), модуль поиска (Search), программа настройки конфигурации (ConfigManager) и так далее.
Далее, если у вас есть отдельные компоненты внутри слоя, то можно для их трассировки выбрать отдельные подкатегории, отделяя от основной категории точкой.
Например, визуальный компонент для отображения облака тегов (который располагается в уровне интерфейса)— UIControls.TagsControl.
Таким образом, при возникновении проблемы с компонентом, с одной стороны вы всегда сможете по журналу определить, какой компонент создал то или иное событие, с другой — более гибко настроить фильтрацию записи в журнал событий только по выбранному компоненту.
Протоколирование — важная функция в любом приложении и требует внимательного анализа и проектирования. Несмотря на то, что трассировка обычно не описывается в требованиях, правильное ее использование может в значительной степени ускорить процесс обнаружения и исправление дефектов на тестовой и рабочей среде.
Данные выкладки — это мои практика и наблюдения, и, соответственно, у вас могут быть свой опыт и своя методика по использованию протоколирования (и трассировки в частности). С удовольствием выслушаю критические отзывы и замечания для улучшения рекомендаций.
Автор: PavelN
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/programmirovanie/14132
Ссылки в тексте:
[1] Lazy logger levels: http://lukas.zapletalovi.com/2012/01/lazy-logger-levels.html
[2] NLog: http://nlog-project.org/wiki/Tutorial
[3] http://dtf.ru/articles/read.php?id=36547: http://dtf.ru/articles/read.php?id=36547
[4] http://www.codeart.ru/2011/02/23/kakim-dolzhen-byt-pravilnyj-log-fajl/: http://www.codeart.ru/2011/02/23/kakim-dolzhen-byt-pravilnyj-log-fajl/
[5] http://www.informit.com/guides/content.aspx?g=dotnet&seqNum=228: http://www.informit.com/guides/content.aspx?g=dotnet&seqNum=228
[6] http://en.wikipedia.org/wiki/Tracing_(software): http://en.wikipedia.org/wiki/Tracing_(software)
[7] http://www.codeproject.com/Articles/42354/The-Art-of-Logging: http://www.codeproject.com/Articles/42354/The-Art-of-Logging
[8] http://habrahabr.ru/post/98638/: http://habrahabr.ru/post/98638/
Нажмите здесь для печати.