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

в 7:01, , рубрики: abap, logging, sap, отладка, разработка

Каждый программист в своей жизни должен хотя бы раз написать свой собственный логгер.
Народное изречение

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

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

Стандарт SAP

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Пример кода и результат в SLG1 (Просмотр журнала)

Исходный код на GitHub Gist: z_log_test.abap

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

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

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

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

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

При просмотре это выглядит следующим образом

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

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

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

Проектируя свой велосипед, я старался найти оптимальное сочетание функциональности и удобства. Получилось реализовать:

  • Запись сообщений из классов и просто текстом из строки
  • Разделение по важности, уровням детализации, задание критерий сортировки
  • Фильтр сообщений с заданным уровнем детализации до записи в лог
  • Лёгкий способ определения собственной логики отображения деталей сообщений

Использование

Для начала необходимо получить экземпляр объекта с помощью статического метода 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

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js