Каждый программист в своей жизни должен хотя бы раз написать свой собственный логгер.
Народное изречение
Сегодня мне хотелось бы рассказать, как использовать журнал приложений в своих разработках, а ещё предложить сообществу очередной велосипед, призванный сделать жизнь немного комфортнее.
Итак, Application Log, также известный как SLG0
и SLG1
…
Стандарт SAP
Журнал приложения – отличное подспорье в отладке и поддержке новых разработок, особенно фоновых задач, веб-сервисов и интерфейсов на технологии WebDynpro, то есть в тех случаях, когда не всегда возможно или просто неудобно использовать отладчик. Журнал – стандартная функциональность SAP, поэтому он всегда готов к вашим услугам.
Просмотреть журнал можно в транзакции SLG1
:
В верхней части отображаются журналы за указанный период, в нижней – сообщения, записанные в выбранный журнал.
Ведение журналов
У каждого журнала есть два основных атрибута: объект и подобъект. Это позволяет разделить всю массу журналов, создаваемых в системе, по области разработки и конкретному приложению, например: объект Z_WEB_SERVICES
и подобъект EXCHANGE_RATE
для сервиса по приёму курсов валют.
Шаг 2. Затем для нового объекта, в дереве слева выбираются «Подобъекты», и создаётся подобъект:
Как этим пользоваться
Чтобы добавить в своё приложение поддержку журнала, достаточно использовать следующие функциональные модули:
BAL_LOG_CREATE
– создаёт новый журнал и возвращает его идентификаторBAL_LOG_MSG_ADD
– добавляет сообщение в журнал по идентификаторуBAL_DB_SAVE
– сохраняет журналы с указанными идентификаторами в базе данных
Кстати, BAL_DB_SAVE
принимает на вход передаётся список идентификаторов и позволяет сохранить несколько журналов сразу.
Подробнее о сообщениях
В предыдущих примерах журнал мало чем отличается от простого текстового файла. Однако, в журналах SAP сообщение обладает большим набором свойств, чем дата и текст, и каждое из них можно использовать для фильтрации и группировки записей при просмотре журнала, некоторые из них представлены на схеме:
- Тип сообщения – от этого параметра зависит цвет значка при просмотре журнала
- Уровень важности – записи автоматически разделяются на категорий по этому признаку
- Критерий сортировки – слово из трёх символов, признак для группировки и сортировки сообщений
- Уровень детализации – число от 1 до 9 включительно, может участвовать в фильтрах
- Дополнительная информация – произвольный набор параметров и ссылка на функциональный модуль или процедуру для его отображения. Может использоваться, например, чтобы прикрепить HTTP заголовок ответа сервера к сообщению об ошибке передачи данных, или для вызова транзакции с параметрами
Ещё один логгер
Чем больше используется свойств сообщений, тем больше разрастается код журналирования, по сути второстепенный. Для решения этой проблемы, да и просто ради удобства, разработчики часто создают вспомогательные подпрограммы в отдельных инклудах или пишут свои функциональные модули и классы.
Проектируя свой велосипед, я старался найти оптимальное сочетание функциональности и удобства. Получилось реализовать:
- Запись сообщений из классов и просто текстом из строки
- Разделение по важности, уровням детализации, задание критерий сортировки
- Фильтр сообщений с заданным уровнем детализации до записи в лог
- Лёгкий способ определения собственной логики отображения деталей сообщений
Использование
Для начала необходимо получить экземпляр объекта с помощью статического метода INSTANTIATE
.
Аргументы – объект, подобъект и внешний идентификатор:
CALL METHOD zbc_cl_log=>instantiate
EXPORTING
iv_object = gc_object
iv_subobject = gc_subobject
iv_external_id = gc_external_id
RECEIVING
ro_log = go_log.
Параметр внешний идентификатор отображается как текст в отдельном столбце списка журналов и помогает найти глазами нужный.
Запись сообщений в лог производится методом WRITE
:
CALL METHOD go_log->write
EXPORTING
iv_type = zbc_cl_log=>info
iv_text = 'Document Source (XML)'
iv_class = zbc_cl_log=>class_additional_information
iv_level = zbc_cl_log=>level_info
iv_sort = 'XML'
iv_details = gv_xml_b
iv_viewer = 'ZBC_LOG_VIEWER_XML_XSTRING'.
Уровень фильтра сообщений до записи в журнал определяется с помощью метода THRESHOLD
, единственный параметр которого может принимать любое значение из определённых констант LEVEL_*
или LEVEL_NO_THRESHOLD
– в этом случае все сообщения будут записаны. По моим наблюдениям, журналов всегда создаётся очень много, и рано или поздно наступает момент, когда их масса сказывается на общей производительности системы. Фильтр по уровню позволяет реализовать отключение записи «лишних» в данный момент деталей.
Для передачи деталей сообщения используется IV_DETAILS
, а имя функционального модуля, который отвечает за отображение отображение этих данных по требованию – IV_VIEWER
. Внутри метода WRITE
происходит сериализация данных, переданных в IV_DETAILS TYPE ANY
, в XML с помощью трансформации ID
, а в момент обращения к ним при просмотре, данные распаковываются и передаются в указанный функциональный модуль.
Такой подход порождает несколько особенностей:
- подаваемое в метод
WRITE
значение должно быть словарного или элементарного типа; - функциональный модуль просмотра должен объявлять параметр такого же типа;
- этот параметр должен называться
I_DATA
.
GV_XML_B
имеет тип XString, то интерфейс функционального модуля будет следующим:
FUNCTION zbc_log_viewer_xml_xstring .
*"----------------------------------------------------------------------
*"*"Local Interface:
*" IMPORTING
*" REFERENCE(I_DATA) TYPE XSTRING
*"----------------------------------------------------------------------
CALL FUNCTION 'DISPLAY_XML_STRING'
EXPORTING
xml_string = i_data
EXCEPTIONS
OTHERS = 0.
ENDFUNCTION.
Вместо заключения
Пока что мне не пришлось попробовать это решение на своём проекте, и почти наверняка в нём есть баги, недочёты или даже ошибки, которые ещё не были замечены, и я буду благодарен за любые комментарии по коду и дизайну разработки. Исходники доступны на GitHub в виде файлов Nugget и Slinkee – установить себе можно с помощью SAPlink, средства обмена кодом ABAP.
Репозиторий GitHub: https://github.com/yaruson/ZBC_LOG_UTILS
Домашняя страница SAPlink: https://www.assembla.com/spaces/saplink/wiki
Автор: Yaruson