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

ABAP Cloud - Logging

1851

In this article, let's take a look at the topic of logging and how it works under ABAP Cloud, and we'll look at the differences and similarities.



Logging messages and error states is an important part of development in ABAP, especially when processing is running in the background and the user wants to look at the logs. The application log has been in the system for a long time. In this article, we'll look at the similarities and differences when it comes to developing in ABAP Cloud.

 

Introduction

ABAP Cloud is the new development model for Clean Core and Cloud Ready applications and does away with many obsolete things in the ABAP programming language. This means that the developer has to learn a lot of new things again and stick to the released SAP APIs. In this article we take a closer look at logging in the system and how it works under ABAP Cloud. If you want to create a development in TIER-1 that requires logging and saving messages, then the following sections will be important for you.

 

Classic ABAP

To remind you once again how it works in classic ABAP development and what objects we use there. Basically you use the two transactions SLG0 for the configuration and SLG1 to evaluate the log. The configuration is transported through the system in order to make the log available in test and production.

If you also want to store messages in the database, you need an object and subobject for logging. You then create a handle with BAL_LOG_CREATE, which you use to accept messages with BAL_LOG_MSG_ADD and finally write the messages to the database with BAL_DB_SAVE. The functions mentioned are the classic function modules.

 

Creation

In the following subsections we describe the new system via ADT, but also the old way via the ABAP API, if, for example, the release is still at an old level and the appropriate ADT APIs are not available.

 

ABAP Development Tools

The first innovation is the creation of the log object in the editor, for this we need the ABAP development tools. And create a new object. To do this, go to the package in the Project Explorer and select “New -> Other ABAP Repository Object” from the context menu. Then we can search for log. If you don't find an entry here, you can continue with the "API" step.

 

The next step is to give the object a name and description. Confirm accordingly in the next step and assign the new object to a transport order.

 

In the last step we end up in the editor for the application log, here you can use the "Add..." button to adopt one or more sub-objects for the logging.

 

In an older version, the editor was a JSON file and wasn't quite as easy to maintain. Depending on the release, the editor could look more or less similar.

 

API

Creating it via the API is quite simple and can be done with one or two calls. To do this, you need the class CL_BALI_OBJECT_HANDLER to create an instance and provide the class with the necessary information. The same object as above is created by this call:

DATA(lo_ohandler) = cl_bali_object_handler=>get_instance( ).

lo_ohandler->create_object( iv_object            = 'ZBS_DEMO_LOG_OBJECT'
                            iv_object_text       = 'Demo Log Object'
                            it_subobjects        = VALUE #(
                                ( subobject = 'TEST' subobject_text = 'Subobject for Logging' ) )
                            iv_package           = 'ZBS_DEMO_LOGGING'
                            iv_transport_request = '<TRANSPORT_REQUEST>' ).

 

Hint: If it is neither possible to create it via ADT nor via the API, your system is probably too old. You need at least an S/4 system for this.

 

Logging

If you would like to know which successors there are for the BAL objects, you can do this using our Cloudification Repository Viewer, where the appropriate successors will be displayed.

 

Generate log

To work with the log, we need the CL_BALI_LOG class to create an instance using the CREATE method. The following example:

" Create log object
DATA(lo_log) = cl_bali_log=>create( ).

" Create and set header
DATA(lo_header) = cl_bali_header_setter=>create( object      = 'ZBS_DEMO_LOG_OBJECT'
                                                 subobject   = 'TEST'
                                                 external_id = cl_system_uuid=>create_uuid_c32_static( )
)->set_expiry( expiry_date       = CONV d( cl_abap_context_info=>get_system_date( ) + 7 )
               keep_until_expiry = abap_true ).
lo_log->set_header( lo_header ).

 

First we create an instance of the log, then we create a header with the necessary configuration (object, subobject, external ID). In the example above, we set the expiration date to Today and add a week. Finally, we pass the header to the log instance.

 

Add messages

As a next step, we now want to pass messages to the API. Various objects are available for this:

  • CL_BALI_MESSAGE_SETTER - Takeover of messages
  • CL_BALI_FREE_TEXT_SETTER - Takeover of simple texts
  • CL_BALI_EXCEPTION_SETTER - Takeover of exceptions

 

In the example you will find the different ways in which messages can be passed to the log:

  1. Message from the system variables
  2. Free text
  3. Exception
  4. Classic message
  5. BAPI messages
" System message
MESSAGE s001(zbs_demo_log) INTO DATA(ld_message).
lo_log->add_item( cl_bali_message_setter=>create_from_sy( ) ).

" Free text
DATA(lo_free) = cl_bali_free_text_setter=>create( severity = if_bali_constants=>c_severity_warning
                                                  text     = 'Execution terminated, dataset not found' ).
lo_log->add_item( lo_free ).

" Exception
DATA(lo_exc) = cl_bali_exception_setter=>create( severity  = if_bali_constants=>c_severity_error
                                                 exception = NEW cx_sy_zerodivide( ) ).
lo_log->add_item( lo_exc ).

" Classic Message
DATA(lo_msg) = cl_bali_message_setter=>create(
    severity   = if_bali_constants=>c_severity_status
    id         = 'ZBS_DEMO_LOG'
    number     = '002'
    variable_1 = CONV #( cl_abap_context_info=>get_user_business_partner_id( ) ) ).
lo_log->add_item( lo_msg ).

" BAPIRET2
DATA(lo_bapi) = cl_bali_message_setter=>create_from_bapiret2( VALUE #( type       = 'E'
                                                                       id         = 'ZBS_DEMO_LOG'
                                                                       number     = '002'
                                                                       message_v1 = 'Dummy' ) )
lo_log->add_item( lo_bapi ).

 

Save logs

Finally, the log only needs to be saved. To do this we need the interface to the database with the class CL_BALI_LOG_DB and pass on our log instance. We get the handle using the corresponding method in the log.

" Save logs
cl_bali_log_db=>get_instance( )->save_log( lo_log ).

" Get the handle
rd_result = lo_log->get_handle( ).

 

Read messages

To read the messages from the log we can again use the database interface. To do this we need the handle from the process before it.

DATA(lo_log_db) = cl_bali_log_db=>get_instance( ).
DATA(lo_log) = lo_log_db->load_log( id_id ).
DATA(lt_items) = lo_log->get_all_items( ).

 

Last but not least, we output the texts to the console, along with the following source code:

LOOP AT lt_items INTO DATA(ls_item).
  out->write( ls_item-item->get_message_text( ) ).
ENDLOOP.

 

Hint: To read the messages from the log, the appropriate authorizations are required via the authorization object S_APPL_LOG. In ABAP Cloud this should be done via an IAM app. Then attach these to a business catalog, add and assign them using the “Maintain Business Roles” app.

 

Constants

The IF_BALI_CONSTANTS interface provides you with various constants to classify the messages. Under C_SEVERITY_* you will find the different types of messages and can use them when creating the messages.

 

ABAP Environment / Public Cloud

What does the generic evaluation of the logs in the system actually look like? Unfortunately, we will be a bit disappointed here, as there is currently no evaluation for Z-Logs, such as transaction SLG1. We can save the logs, attach them to application jobs or evaluate them via the standard API in our Fiori application. Maybe SAP will deliver something here in the future and allow a general evaluation of all application logs in the system; the infrastructure would be there.

 

On-Premise / Private Cloud

In the classic system, where we also have access to the SAP GUI, we can still view the configuration of our logging object using the classic transaction SLG0. The special thing here is that the object is only available for display and the actual changes have to be made via ADT:

 

This is exactly how we can evaluate the application log (transaction SLG1) and look at the messages generated. The functionality in the background has remained the same:

 

Complete example

Finally, the complete coding from today's article on how to create and read messages from the application log:

CLASS zcl_bs_demo_handle_messages DEFINITION PUBLIC FINAL CREATE PUBLIC.
  PUBLIC SECTION.
    INTERFACES if_oo_adt_classrun.

  PRIVATE SECTION.
    METHODS create_log_entries
      RETURNING VALUE(rd_result) TYPE if_bali_log=>ty_handle
      RAISING   cx_static_check.

    METHODS read_log_entries
      IMPORTING id_id            TYPE if_bali_log=>ty_handle
      RETURNING VALUE(rt_result) TYPE if_bali_log=>ty_item_table
      RAISING   cx_static_check.
ENDCLASS.


CLASS zcl_bs_demo_handle_messages IMPLEMENTATION.
  METHOD if_oo_adt_classrun~main.
    TRY.
        " Log messages and get handle
        DATA(ld_id) = create_log_entries( ).
        out->write( |Log created: { ld_id }| ).

        " Read messages from handle
        DATA(lt_items) = read_log_entries( ld_id ).
        LOOP AT lt_items INTO DATA(ls_item).
          out->write( ls_item-item->get_message_text( ) ).
        ENDLOOP.

      CATCH cx_root INTO DATA(lo_err).
        out->write( lo_err->get_longtext( ) ).
    ENDTRY.
  ENDMETHOD.


  METHOD create_log_entries.
    " Create log object
    DATA(lo_log) = cl_bali_log=>create( ).

    " Create and set header
    DATA(lo_header) = cl_bali_header_setter=>create( object      = 'ZBS_DEMO_LOG_OBJECT'
                                                     subobject   = 'TEST'
                                                     external_id = cl_system_uuid=>create_uuid_c32_static( )
    )->set_expiry( expiry_date       = CONV d( cl_abap_context_info=>get_system_date( ) + 7 )
                   keep_until_expiry = abap_true ).
    lo_log->set_header( lo_header ).

    " System message
    MESSAGE s001(zbs_demo_log) INTO DATA(ld_message).
    lo_log->add_item( cl_bali_message_setter=>create_from_sy( ) ).

    " Free text
    DATA(lo_free) = cl_bali_free_text_setter=>create( severity = if_bali_constants=>c_severity_warning
                                                      text     = 'Execution terminated, dataset not found' ).
    lo_log->add_item( lo_free ).

    " Exception
    DATA(lo_exc) = cl_bali_exception_setter=>create( severity  = if_bali_constants=>c_severity_error
                                                     exception = NEW cx_sy_zerodivide( ) ).
    lo_log->add_item( lo_exc ).

    " Classic Message
    DATA(lo_msg) = cl_bali_message_setter=>create(
        severity   = if_bali_constants=>c_severity_status
        id         = 'ZBS_DEMO_LOG'
        number     = '002'
        variable_1 = CONV #( cl_abap_context_info=>get_user_business_partner_id( ) ) ).
    lo_log->add_item( lo_msg ).

    " BAPIRET2
    DATA(lo_bapi) = cl_bali_message_setter=>create_from_bapiret2( VALUE #( type       = 'E'
                                                                           id         = 'ZBS_DEMO_LOG'
                                                                           number     = '002'
                                                                           message_v1 = 'Dummy' ) ).
    lo_log->add_item( lo_bapi ).

    " Save logs
    cl_bali_log_db=>get_instance( )->save_log( lo_log ).

    " Get the handle
    rd_result = lo_log->get_handle( ).
  ENDMETHOD.


  METHOD read_log_entries.
    DATA(lo_log_db) = cl_bali_log_db=>get_instance( ).

    DATA(lo_log) = lo_log_db->load_log( id_id ).

    rt_result = lo_log->get_all_items( ).
  ENDMETHOD.
ENDCLASS.

 

Conclusion

Logging in ABAP Cloud is based on the same objects and techniques, but gives the whole thing a modern look in the form of classes. When it comes to evaluating messages, the cloud should add some functionality to enable the same possibilities as on-premise.


Included topics:
ABAP CloudABAPApplication LogLog
Comments (0)



And further ...

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


ABAP Cloud - ADT Trees (Overview)

Category - ABAP

What help and overviews are available in the ABAP Development Tools to simplify your life with ABAP Cloud?

12/17/2024

ABAP Cloud - Relevant Objects

Category - ABAP

Which objects are still relevant in ABAP development and which ones can you slowly put away? Find out more here.

11/19/2024

ABAP Cloud - Locks

Category - ABAP

What do you need to set locks for and how can you easily do that in ABAP Cloud? In this article we will look at the process in detail.

11/08/2024

ABAP Cloud - HTTP Client

Category - ABAP

What does the current HTTP client in ABAP Cloud look like? Let's take a look at the new model.

11/01/2024

ABAP Cloud - Key User Apps

Category - ABAP

Key User Extensibility is a part of ABAP Cloud when it comes to extending the core, but how can you use the tools effectively and how do they complement each other?

10/11/2024