Ещё один логгер для SAP

Каждый программист в своей жизни должен хотя бы раз написать свой собственный логгер.
Народное изречение
Сегодня мне хотелось бы рассказать, как использовать журнал приложений в своих разработках, а ещё предложить сообществу очередной велосипед, призванный сделать жизнь немного комфортнее.

Итак, Application Log, также известный как SLG0 и SLG1

Стандарт SAP


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

Просмотреть журнал можно в транзакции SLG1:



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

Ведение журналов

У каждого журнала есть два основных атрибута: объект и подобъект. Это позволяет разделить всю массу журналов, создаваемых в системе, по области разработки и конкретному приложению, например: объект Z_WEB_SERVICES и подобъект EXCHANGE_RATE для сервиса по приёму курсов валют.

Для ведения объектов и подобъектов используется транзакция SLG0
Шаг 1. Запись добавляется в два шага: на первом экране определяется имя объекта:



Шаг 2. Затем для нового объекта, в дереве слева выбираются «Подобъекты», и создаётся подобъект:



Как этим пользоваться

Чтобы добавить в своё приложение поддержку журнала, достаточно использовать следующие функциональные модули:

  • BAL_LOG_CREATE – создаёт новый журнал и возвращает его идентификатор
  • BAL_LOG_MSG_ADD – добавляет сообщение в журнал по идентификатору
  • BAL_DB_SAVE – сохраняет журналы с указанными идентификаторами в базе данных

Кстати, BAL_DB_SAVE принимает на вход передаётся список идентификаторов и позволяет сохранить несколько журналов сразу.

Пример кода и результат в SLG1 (Просмотр журнала)
Исходный код на GitHub Gist: z_log_test.abap



Подробнее о сообщениях


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



  1. Тип сообщения – от этого параметра зависит цвет значка при просмотре журнала
  2. Уровень важности – записи автоматически разделяются на категорий по этому признаку
  3. Критерий сортировки – слово из трёх символов, признак для группировки и сортировки сообщений
  4. Уровень детализации – число от 1 до 9 включительно, может участвовать в фильтрах
  5. Дополнительная информация – произвольный набор параметров и ссылка на функциональный модуль или процедуру для его отображения. Может использоваться, например, чтобы прикрепить 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
Поделиться публикацией

Похожие публикации

Комментарии 0

Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

Самое читаемое