Add Data Container - SchwarzIT/sap-usi-logging-api Wiki

Data containers can be used to attach virtually any kind of data to a log message. The data will accessible in SLG1 while displaying a log.

Depending on the type of the data container, it might display detail information or navigate somewhere.

alt text

The screenshot shows a list of data containers, that have been attached to a single log message.

How to implement a data container

All data containers need to implement the interface /USI/IF_BAL_DATA_CONTAINER or - to be even more precise - one of its comprehensive interfaces.

Interface Purpose
/USI/IF_BAL_DATA_CONTAINER Defines the methods that the data container will need to interact with the rest of the API.

It does NOT contain a method to do anything with the internally stored data. Such methods will be added by the comprehensive interfaces.
/USI/IF_BAL_DATA_CONTAINER_NAV For data containers, that are navigating somewhere (e.g. jump to a source code position)
/USI/IF_BAL_DATA_CONTAINER_RND For data containers, that will render their data using a GUI_CONTAINER provided by the API

Methods to implement

/USI/IF_BAL_DATA_CONTAINER

IS_MULTIPLE_USE_ALLOWED

Different types of containers may have differnt cardinalities:

  • [0-1] e.g. source code position of an exception
  • [0-n] e.g. internal tables

This method has to return ABAP_TRUE for cardinality [0-n] and ABAP_FALSE for [0-1].

GET_CLASSNAME

Has to return the exact classname of the implementing class.

CAUTION: The classname is used as a key value by the persistence layer. It will also be used to call method deserialize dynamically when loading log data for display. Changing it later will make already stored containers inaccessible!

GET_DESCRIPTION

Has to return the describing short text of a container, that will be displayed in the tree control in SLG1.

HINT: If your data container allows multiple instances (cardinality [0-n]) you might want to add individual label texts to every single container instance to be able to tell them apart. Single-use-containers can use static texts (e.g. text symbols of the class).

If you need dynamic texts, it is highly recommended to use a translatable text container for that purpose. This will ensure, that you will see these labels in a language that you understand when displaying the log.

Currently two text containers are shipped with the API:

  • /USI/CL_BAL_TC_LITERAL_C40
    • Text will be stored 'as is' on the database
    • Consider using english texts when using this container
  • /USI/CL_BAL_TC_REPORT_TEXT_C40
    • Dynamic reference to a text symbol
    • Text will be read when displaying data in SLG1
    • Implements a fallback strategy for missing translations and will display the text in the most reasonable language (As per system customizing)
      • Fallback #1: Fallback languages defined in T002C-LAKETT. Up to two fallback languages are supported by this fallback mechanism.
      • Fallback #2: General language priority defined in table T778L.
" Example: how to integrate translatable text containers into a data container
CLASS zcl_bal_dc_my_container DEFINITION PUBLIC FINAL CREATE PUBLIC.
  PUBLIC SECTION.
    INTERFACES: [...]
 
    METHODS constructor
      IMPORTING
        i_container_title TYPE REF TO /usi/if_bal_text_container_c40 OPTIONAL            " Import container title
        i_container_data  TYPE string.
 
  PRIVATE SECTION.
    DATA: container_title TYPE REF TO /usi/if_bal_text_container_c40,                   
          container_data  TYPE string.
ENDCLASS.
 
CLASS zcl_bal_dc_my_container IMPLEMENTATION.
  METHOD constructor.
    container_title = i_container_title.                                                 " Store it internally
    container_data  = i_container_data.
  ENDMETHOD.
 
  METHOD /usi/if_bal_data_container~get_description.
    DATA container_title_text TYPE /usi/if_bal_text_container_c40=>ty_text.
 
    r_result = TEXT-des. " Prefix for your container type (e.g. "HTML-Document")
    IF container_title IS BOUND.                                                         " Add text to description
      container_title_text = container_title->get_text( ).
      CONCATENATE r_result `: ` container_title_text INTO r_result IN CHARACTER MODE.
    ENDIF.
  ENDMETHOD.
  [...]
ENDCLASS.

SERIALIZE

Converts the internal data of the instance into an XML-String.

HINT: Use transformation ID to convert data to XML

" Example without text container
METHOD /usi/if_bal_data_container~serialize.
  CALL TRANSFORMATION id
    SOURCE container_data = container_data
    RESULT XML r_result.
ENDMETHOD.
" Example with text container
METHOD /usi/if_bal_data_container~serialize.
  DATA: container_title_classname  TYPE /usi/bal_text_cont_classname,
        serialized_container_title TYPE /usi/bal_xml_string.
 
  " Serialize container title
  IF container_title IS BOUND.
    container_title_classname  = container_title->get_classname( ).
    serialized_container_title = container_title->serialize( ).
  ENDIF.
 
  " Serialize container data and serialized container title
  CALL TRANSFORMATION id
    SOURCE container_data             = container_data
           container_title_classname  = container_title_classname
           serialized_container_title = serialized_container_title
    RESULT XML r_result.
ENDMETHOD.

DESERIALIZE

Recreates an instance from an XML-String

HINT: Use transformation ID to convert XML to internal format.

" Example without text container
METHOD /usi/if_bal_data_container~deserialize.
  DATA: container_data       TYPE string,
        transformation_error TYPE REF TO cx_transformation_error.
 
  " Convert XML to internal format
  TRY.
      CALL TRANSFORMATION id
        SOURCE XML i_serialized_data_container
        RESULT container_data = container_data.
    CATCH cx_transformation_error INTO transformation_error.
      " ALWAYS (!!!) catch transformation errors!
      " This will avoid short dumps in SLG1, if something is wrong with the XML conversion.
      RAISE EXCEPTION TYPE /usi/cx_bal_type_mismatch
        EXPORTING
          textid   = /usi/cx_bal_type_mismatch=>/usi/cx_bal_type_mismatch
          previous = transformation_error.
  ENDTRY.
 
  " Use data to recreate the container instance
  CREATE OBJECT r_result TYPE zcl_bal_dc_my_container
    EXPORTING
      i_container_data  = container_data.
ENDMETHOD.
" Example with text container
METHOD /usi/if_bal_data_container~deserialize.
  DATA: container_data             TYPE string,
        container_title            TYPE REF TO /usi/if_bal_text_container_c40,
        container_title_classname  TYPE /usi/bal_text_cont_classname,
        exception                  TYPE REF TO cx_root,
        exception_text             TYPE string,
        serialized_container_title TYPE /usi/bal_xml_string.
 
  " Convert XML to internal format
  TRY.
      CALL TRANSFORMATION id
        SOURCE XML i_serialized_data_container
        RESULT container_data             = container_data
               container_title_classname  = container_title_classname
               serialized_container_title = serialized_container_title.
    CATCH cx_transformation_error INTO exception.
      " ALWAYS (!!!) catch transformation errors!
      " This will avoid short dumps in SLG1, if something is wrong with the XML conversion.
      RAISE EXCEPTION TYPE /usi/cx_bal_type_mismatch
        EXPORTING
          textid   = /usi/cx_bal_type_mismatch=>/usi/cx_bal_type_mismatch
          previous = exception.
  ENDTRY.
 
  " Recreate the text container, if needed
  IF container_title_classname IS NOT INITIAL.
    TRY.
        CALL METHOD (container_title_classname)=>/usi/if_bal_text_container_c40~deserialize
          EXPORTING
            i_serialized_text_container = serialized_container_title
          RECEIVING
            r_result                    = container_title.
      CATCH cx_sy_dyn_call_error
            /usi/cx_bal_root INTO exception.
        exception_text = exception->get_text( ).
        ASSERT ID   /usi/bal_log_writer
          FIELDS    exception_text
          CONDITION exception IS NOT BOUND.
 
        CLEAR container_title.
    ENDTRY.
  ENDIF.
 
  " Use data to recreate the container instance
  CREATE OBJECT r_result TYPE zcl_bal_dc_my_container
    EXPORTING
      i_container_title = container_title
      i_container_data  = container_data.
ENDMETHOD.

/USI/IF_BAL_DATA_CONTAINER_NAV

NAVIGATE

Jumps to e.g. a source code position, but could also call transactions, etc. Implement the navigation you need.

/USI/IF_BAL_DATA_CONTAINER_RND

RENDER

Renders the internal data of the data container.

The API will provide an instance of class CL_GUI_CONTAINER that has to be used as the parent for all controls used to display the data.

Integration

Data containers are assigned to log levels and will only be saved, if the current log level meets the required minimum (see: Customizing -> Log Levels -> Relevant Data Containers).

⚠️ **GitHub.com Fallback** ⚠️