This is a test message to test the length of the message box.
Login
|
ABAP Logging Performance
Created by Software-Heroes

ABAP Quick - Logging Performance

303

What about the performance of the BAL log in the ABAP Cloud world? Let's look at three solutions and measure their performance in different scenarios.

Advertising


In this article, we measure the performance of the current ABAP Cloud Logging classes and examine which class is worthwhile for which scenarios. The article was inspired by a comment on the XCO Logging article.

 

Introduction

A few articles back, we looked at the XCO Logging class and compared it with the existing classes. But what about the performance when using these classes, and what impact does this have on our application operations? To do this, we will look at various scenarios and compare them at the end of the article.

 

Scenario

In our test scenario, we want to look at the ABAP Cloud classes CL_BALI_LOG and XCO_CP_BAL. Additionally, we will also measure the behavior of the Open Source project ABAP Message Logger, which focuses more on message processing. This project is also fundamentally based on the CL_BALI_LOG class, but it further integrates the logic. We will look at the following test cases:

  • Without storage (little) - Transfer of 500 messages to the object
  • Without storage (lots) - Transfer of 5000 messages to the object
  • Storage (little) - Transfer of 500 messages to the object and storage of the application log
  • Storage (lots) - Transfer of 5000 messages to the object and storage of the application log
  • Second connection (little) - We use the second database connection for storage and work with 500 messages
  • Second connection (lots) - We use the second database connection for storage and work with 5000 messages

 

Setup

For the test setup, we create several methods to generate and manage the various objects for us. First, we divide the different logs into scenarios that we execute sequentially:

  1. CL_BALI_LOG
  2. XCO_CP_BAL
  3. ABAP Message Logger (AML)

 

Start

Using the various helper methods, we process the data, create logs, and save the messages. We later start all tests using the START_SCENARIO method. In this process, we define the type of scenario, the number of messages we want to manage, whether the log should be backed up, and whether a second database connection is used for this purpose.

METHODS start_scenario
  IMPORTING scenario           TYPE i
            number_of_messages TYPE i
            !save              TYPE abap_boolean
            db_connection      TYPE abap_boolean.

 

Create Log

We then create the log using the various predefined methods of the frameworks. With BALI, we create the header and pass it to the log object. With the XCO class, we only need to call the Create method, and with AML, we use the factory with the settings. For all three scenarios, we use a UUID as the external ID.

METHOD create_log.
  DATA(external_id) = CONV cl_bali_header_setter=>ty_external_id( xco_cp=>uuid( )->as( xco_cp_uuid=>format->c32 )->value ).

  CASE scenario.
    WHEN 1.
      bali_log = cl_bali_log=>create( ).
      bali_log->set_header( cl_bali_header_setter=>create( object      = 'Z_AML_LOG'
                                                           subobject   = 'TEST'
                                                           external_id = external_id ) ).
    WHEN 2.
      xco_log = xco_cp_bal=>for->database(
                      )->log->create( iv_object      = 'Z_AML_LOG'
                                      iv_subobject   = 'TEST'
                                      iv_external_id = external_id ).
    WHEN 3.
      aml_log = zcl_aml_log_factory=>create( VALUE #( object                = 'Z_AML_LOG'
                                                      subobject             = 'TEST'
                                                      external_id           = external_id
                                                      use_2nd_db_connection = db_connection ) ).
  ENDCASE.
ENDMETHOD.

 

Passing the message

As a message, we generate a message via the system variables and pass the message into the classes. We chose this form because all classes support it well.

METHOD add_message.
  CASE scenario.
    WHEN 1.
      bali_log->add_item( cl_bali_message_setter=>create_from_sy( ) ).
    WHEN 2.
      xco_log->add_message( xco_cp=>sy->message( )->value ).
    WHEN 3.
      aml_log->add_message_system( ).
  ENDCASE.
ENDMETHOD.

 

Save Log

Save the logs is implemented differently here. With BALI, we need an additional object to save the log, XCO saves the messages immediately, and with AML, we only need to call SAVE, as the remaining logic is abstracted internally.

METHOD save_log.
  CASE scenario.
    WHEN 1.
      cl_bali_log_db=>get_instance( )->save_log( log                   = bali_log
                                                 use_2nd_db_connection = db_connection ).
    WHEN 2.
      " Nothing to do
    WHEN 3.
      aml_log->save( ).
  ENDCASE.
ENDMETHOD.

 

Test Run

In the first step, let's execute each logic once. To do this, we can set the constant TIMES_TO_EXECUTE to one and start the class. This gives us an initial indication of the runtimes of the different components.

 

After the first run with one execution of each, it becomes clear that the architecture of the XCO class is not designed for mass testing. The runtime scales with the number of messages and negatively impacts the overall runtime. Therefore, in the second run, we increase the number of executions to 25, but exclude the XCO class. This time we get the result faster and can already see some initial differences.

 

Comparison

Based on the results, we can now make the following statements about the different classes and frameworks:

  • XCO_CP_BAL - Is the slowest class and offers hardly any settings for recording and storing messages. The more messages need to be stored, the slower the class becomes.
  • Logging - For pure logging without storing the messages, AML is faster than CL_BALI_LOG, because the BAL function modules are not used, but the data is managed internally. If you don't want to persist the messages at all, or only in emergencies, a separate logging solution is recommended.
  • Storage - CL_BALI_LOG is slightly faster when saving, as the internal management and processing of AML consumes some performance.
  • Direct or second connection - The second database connection does not improve performance. It still waits for the save. However, no commit is triggered in the current session, and the messages are written even during a rollback.

 

XCO_CP_BAL is very slow in testing, but the class continuously writes the messages to the log. During a dump, all messages up to that point are available in the log. With the other solutions, no log is written. However, the "emergency logging" function has been now also implemented as an option in AML, the charming advantage of an Open Source project.

 

 

Complete Example

Here you will find the complete example from the article. To execute the class, however, you need a helper class for runtime measurement and the Open Source component. Here is the example shown:

CLASS zcl_bs_demo_performance_log DEFINITION
  PUBLIC FINAL
  CREATE PUBLIC.

  PUBLIC SECTION.
    INTERFACES if_oo_adt_classrun.

  PRIVATE SECTION.
    CONSTANTS times_to_execute TYPE i VALUE 1.
    CONSTANTS messages_small   TYPE i VALUE 500.
    CONSTANTS messages_big     TYPE i VALUE 5000.

    DATA bali_log TYPE REF TO if_bali_log.
    DATA xco_log  TYPE REF TO if_xco_cp_bal_log.
    DATA aml_log  TYPE REF TO zif_aml_log.

    METHODS create_log
      IMPORTING scenario      TYPE i
                db_connection TYPE abap_boolean.

    METHODS add_message
      IMPORTING scenario TYPE i.

    METHODS save_log
      IMPORTING scenario      TYPE i
                db_connection TYPE abap_boolean.

    METHODS start_scenario
      IMPORTING scenario           TYPE i
                number_of_messages TYPE i
                !save              TYPE abap_boolean
                db_connection      TYPE abap_boolean.

ENDCLASS.


CLASS zcl_bs_demo_performance_log IMPLEMENTATION.
  METHOD if_oo_adt_classrun~main.
    DO 3 TIMES.
      DATA(scenario) = sy-index.

*      IF scenario = 2.
*        CONTINUE.
*      ENDIF.

      DATA(lo_run) = NEW zcl_bs_demo_runtime( ).
      DO times_to_execute TIMES.
        start_scenario( scenario           = scenario
                        number_of_messages = messages_small
                        save               = abap_false
                        db_connection      = abap_false ).
      ENDDO.
      out->write( |Small message { scenario } : { lo_run->get_diff( ) }| ).

      lo_run = NEW zcl_bs_demo_runtime( ).
      DO times_to_execute TIMES.
        start_scenario( scenario           = scenario
                        number_of_messages = messages_big
                        save               = abap_false
                        db_connection      = abap_false ).
      ENDDO.
      out->write( |Big message { scenario }   : { lo_run->get_diff( ) }| ).

      lo_run = NEW zcl_bs_demo_runtime( ).
      DO times_to_execute TIMES.
        start_scenario( scenario           = scenario
                        number_of_messages = messages_small
                        save               = abap_true
                        db_connection      = abap_false ).
      ENDDO.
      out->write( |Small save { scenario }    : { lo_run->get_diff( ) }| ).

      lo_run = NEW zcl_bs_demo_runtime( ).
      DO times_to_execute TIMES.
        start_scenario( scenario           = scenario
                        number_of_messages = messages_big
                        save               = abap_true
                        db_connection      = abap_false ).
      ENDDO.
      out->write( |Big save { scenario }      : { lo_run->get_diff( ) }| ).

      lo_run = NEW zcl_bs_demo_runtime( ).
      DO times_to_execute TIMES.
        start_scenario( scenario           = scenario
                        number_of_messages = messages_small
                        save               = abap_true
                        db_connection      = abap_true ).
      ENDDO.
      out->write( |Small 2nd { scenario }     : { lo_run->get_diff( ) }| ).

      lo_run = NEW zcl_bs_demo_runtime( ).
      DO times_to_execute TIMES.
        start_scenario( scenario           = scenario
                        number_of_messages = messages_big
                        save               = abap_true
                        db_connection      = abap_true ).
      ENDDO.
      out->write( |Big 2nd { scenario }       : { lo_run->get_diff( ) }| ).
    ENDDO.
  ENDMETHOD.


  METHOD start_scenario.
    create_log( scenario      = scenario
                db_connection = db_connection ).

    DO number_of_messages TIMES.
      MESSAGE s001(zbs_demo_xco) WITH 'Test' sy-index INTO DATA(message) ##NEEDED.
      add_message( scenario ).
    ENDDO.

    IF save = abap_true.
      save_log( scenario      = scenario
                db_connection = db_connection ).
    ENDIF.
  ENDMETHOD.


  METHOD create_log.
    DATA(external_id) = CONV cl_bali_header_setter=>ty_external_id( xco_cp=>uuid( )->as( xco_cp_uuid=>format->c32 )->value ).

    CASE scenario.
      WHEN 1.
        IF bali_log IS NOT INITIAL.
          bali_log->release_memory( ).
        ENDIF.

        bali_log = cl_bali_log=>create( ).
        bali_log->set_header( cl_bali_header_setter=>create( object      = 'Z_AML_LOG'
                                                             subobject   = 'TEST'
                                                             external_id = external_id ) ).
      WHEN 2.
        xco_log = xco_cp_bal=>for->database(
                        )->log->create( iv_object      = 'Z_AML_LOG'
                                        iv_subobject   = 'TEST'
                                        iv_external_id = external_id ).
      WHEN 3.
        aml_log = zcl_aml_log_factory=>create( VALUE #( object                = 'Z_AML_LOG'
                                                        subobject             = 'TEST'
                                                        external_id           = external_id
                                                        use_2nd_db_connection = db_connection ) ).
    ENDCASE.
  ENDMETHOD.


  METHOD add_message.
    CASE scenario.
      WHEN 1.
        bali_log->add_item( cl_bali_message_setter=>create_from_sy( ) ).
      WHEN 2.
        xco_log->add_message( xco_cp=>sy->message( )->value ).
      WHEN 3.
        aml_log->add_message_system( ).
    ENDCASE.
  ENDMETHOD.


  METHOD save_log.
    CASE scenario.
      WHEN 1.
        cl_bali_log_db=>get_instance( )->save_log( log                   = bali_log
                                                   use_2nd_db_connection = db_connection ).
      WHEN 2.
        " Nothing to do
      WHEN 3.
        aml_log->save( ).
    ENDCASE.
  ENDMETHOD.
ENDCLASS.

 

Conclusion

The runtime of the XCO class was very noticeable and unexpected. Therefore, the class was excluded during the course of the test, although it still offers certain advantages. You should always consider your logging goals when implementing the code.


Included topics:
QuickLoggingPerformanceABAP Cloud
Comments (0)



And further ...

Are you satisfied with the content of the article? We post new content in the ABAP area every Tuesday and Friday and irregularly in all other areas. Take a look at our tools and apps, we provide them free of charge.


ABAP in Practice - Fiori Data incorrect

Category - ABAP

In this short practical example, we'll look at a Fiori error. Here, the data is displayed incorrectly in the UI, even though everything else appears to be correct. The trail leads us in a different direction through the RAP stack.

10/10/2025

ABAP Quick - Handling of Function modules

Category - ABAP

How do you actually handle function modules and error handling within ABAP? In this short tip, we'll also look at handling them within the context of RFC.

08/26/2025

ABAP Quick - Generic Data Types

Category - ABAP

What exactly distinguishes CLIKE from CSEQUENCE? Generic types can sometimes be a bit opaque, and as ABAP developers, we might choose a type that's too generic.

08/12/2025

BTP - Quick Deployment

Category - ABAP

Want to make Fiori Elements apps available even faster after RAP modeling? Quick Deployment is now possible.

07/18/2025

Recycling Heroes (Explained)

Category - ABAP

What do the Recycling Heroes have to do with modern ABAP development and ABAP Cloud? In this article, we provide insights into the idea.

07/15/2025