The Application Log (BAL) is the standard framework for persistent logging in SAP. Logs are stored in the database and can be displayed via transaction SLG1.
Basic Concept
| Element | Description |
|---|---|
| Log Object | Grouping (e.g., application) - maintain in SLG0 |
| Sub-Object | Subcategory of the Log Object |
| Log Handle | Unique ID of a log instance |
| Message | Individual log message |
| SLG1 | Transaction for log display |
Message Types
| Type | Meaning | Icon |
|---|---|---|
| A | Abort | Red |
| E | Error | Red |
| W | Warning | Yellow |
| I | Information | Blue |
| S | Success | Green |
Examples
1. Create a Simple Log
DATA: lv_log_handle TYPE balloghndl, ls_log TYPE bal_s_log.
" Log headerls_log-object = 'ZTEST'. " Log object (from SLG0)ls_log-subobject = 'PROCESS'. " Sub-objectls_log-aldate = sy-datum.ls_log-altime = sy-uzeit.ls_log-aluser = sy-uname.ls_log-alprog = sy-repid.ls_log-extnumber = 'My Processing 001'.
" Create logCALL FUNCTION 'BAL_LOG_CREATE' EXPORTING i_s_log = ls_log IMPORTING e_log_handle = lv_log_handle EXCEPTIONS log_header_inconsistent = 1 OTHERS = 2.
IF sy-subrc <> 0. RETURN.ENDIF.
" Add messageDATA: ls_msg TYPE bal_s_msg.
ls_msg-msgty = 'S'.ls_msg-msgid = 'ZMYAPP'.ls_msg-msgno = '001'.ls_msg-msgv1 = 'Processing started'.
CALL FUNCTION 'BAL_LOG_MSG_ADD' EXPORTING i_log_handle = lv_log_handle i_s_msg = ls_msg EXCEPTIONS log_not_found = 1 msg_inconsistent = 2 OTHERS = 3.
" Additional messagesls_msg-msgty = 'I'.ls_msg-msgv1 = '100 records processed'.CALL FUNCTION 'BAL_LOG_MSG_ADD' EXPORTING i_log_handle = lv_log_handle i_s_msg = ls_msg.
ls_msg-msgty = 'S'.ls_msg-msgv1 = 'Processing completed'.CALL FUNCTION 'BAL_LOG_MSG_ADD' EXPORTING i_log_handle = lv_log_handle i_s_msg = ls_msg.
" Save logCALL FUNCTION 'BAL_DB_SAVE' EXCEPTIONS log_not_found = 1 save_not_allowed = 2 numbering_error = 3 OTHERS = 4.
IF sy-subrc = 0. COMMIT WORK. WRITE: / 'Log saved'.ENDIF.2. OO Approach with CL_BAL_LOG
CLASS zcl_application_log DEFINITION. PUBLIC SECTION. METHODS: constructor IMPORTING iv_object TYPE balobj_d iv_subobject TYPE balsubobj iv_extnumber TYPE balnrext OPTIONAL.
METHODS: add_success IMPORTING iv_message TYPE string.
METHODS: add_error IMPORTING iv_message TYPE string.
METHODS: add_warning IMPORTING iv_message TYPE string.
METHODS: add_info IMPORTING iv_message TYPE string.
METHODS: add_exception IMPORTING ix_error TYPE REF TO cx_root.
METHODS: save RETURNING VALUE(rv_success) TYPE abap_bool.
METHODS: display.
METHODS: get_messages RETURNING VALUE(rt_messages) TYPE bapiret2_t.
PRIVATE SECTION. DATA: mv_log_handle TYPE balloghndl.
METHODS: add_message IMPORTING iv_type TYPE sy-msgty iv_message TYPE string.ENDCLASS.
CLASS zcl_application_log IMPLEMENTATION. METHOD constructor. DATA: ls_log TYPE bal_s_log.
ls_log-object = iv_object. ls_log-subobject = iv_subobject. ls_log-aldate = sy-datum. ls_log-altime = sy-uzeit. ls_log-aluser = sy-uname. ls_log-alprog = sy-repid. ls_log-extnumber = iv_extnumber.
CALL FUNCTION 'BAL_LOG_CREATE' EXPORTING i_s_log = ls_log IMPORTING e_log_handle = mv_log_handle EXCEPTIONS OTHERS = 1. ENDMETHOD.
METHOD add_message. DATA: ls_msg TYPE bal_s_msg.
" Free message ls_msg-msgty = iv_type. ls_msg-msgid = 'ZLOG'. ls_msg-msgno = '000'. ls_msg-msgv1 = iv_message(50). IF strlen( iv_message ) > 50. ls_msg-msgv2 = iv_message+50(50). ENDIF. IF strlen( iv_message ) > 100. ls_msg-msgv3 = iv_message+100(50). ENDIF. IF strlen( iv_message ) > 150. ls_msg-msgv4 = iv_message+150(50). ENDIF.
CALL FUNCTION 'BAL_LOG_MSG_ADD' EXPORTING i_log_handle = mv_log_handle i_s_msg = ls_msg EXCEPTIONS OTHERS = 1. ENDMETHOD.
METHOD add_success. add_message( iv_type = 'S' iv_message = iv_message ). ENDMETHOD.
METHOD add_error. add_message( iv_type = 'E' iv_message = iv_message ). ENDMETHOD.
METHOD add_warning. add_message( iv_type = 'W' iv_message = iv_message ). ENDMETHOD.
METHOD add_info. add_message( iv_type = 'I' iv_message = iv_message ). ENDMETHOD.
METHOD add_exception. DATA: ls_msg TYPE bal_s_msg.
ls_msg-msgty = 'E'. ls_msg-msgid = 'ZLOG'. ls_msg-msgno = '001'. ls_msg-msgv1 = ix_error->get_text( )(50).
CALL FUNCTION 'BAL_LOG_MSG_ADD' EXPORTING i_log_handle = mv_log_handle i_s_msg = ls_msg EXCEPTIONS OTHERS = 1. ENDMETHOD.
METHOD save. DATA: lt_log_handles TYPE bal_t_logh.
APPEND mv_log_handle TO lt_log_handles.
CALL FUNCTION 'BAL_DB_SAVE' EXPORTING i_t_log_handle = lt_log_handles EXCEPTIONS log_not_found = 1 save_not_allowed = 2 numbering_error = 3 OTHERS = 4.
rv_success = xsdbool( sy-subrc = 0 ).
IF rv_success = abap_true. COMMIT WORK. ENDIF. ENDMETHOD.
METHOD display. DATA: lt_log_handles TYPE bal_t_logh, ls_profile TYPE bal_s_prof.
APPEND mv_log_handle TO lt_log_handles.
CALL FUNCTION 'BAL_DSP_PROFILE_STANDARD_GET' IMPORTING e_s_display_profile = ls_profile.
CALL FUNCTION 'BAL_DSP_LOG_DISPLAY' EXPORTING i_t_log_handle = lt_log_handles i_s_display_profile = ls_profile EXCEPTIONS OTHERS = 1. ENDMETHOD.
METHOD get_messages. DATA: lt_msg TYPE bal_t_msg, ls_msg TYPE bal_s_msg.
CALL FUNCTION 'BAL_LOG_MSG_READ' EXPORTING i_log_handle = mv_log_handle IMPORTING e_t_msg = lt_msg EXCEPTIONS OTHERS = 1.
LOOP AT lt_msg INTO ls_msg. APPEND VALUE bapiret2( type = ls_msg-msgty id = ls_msg-msgid number = ls_msg-msgno message_v1 = ls_msg-msgv1 message_v2 = ls_msg-msgv2 message_v3 = ls_msg-msgv3 message_v4 = ls_msg-msgv4 ) TO rt_messages. ENDLOOP. ENDMETHOD.ENDCLASS.
" UsageDATA(lo_log) = NEW zcl_application_log( iv_object = 'ZTEST' iv_subobject = 'BATCH' iv_extnumber = |Processing { sy-datum }|).
lo_log->add_success( 'Processing started' ).lo_log->add_info( '500 records loaded' ).
TRY. " Processing... lo_log->add_success( 'Processing successful' ). CATCH cx_root INTO DATA(lx_error). lo_log->add_exception( lx_error ).ENDTRY.
IF lo_log->save( ). lo_log->display( ).ENDIF.3. Create Log Object in SLG0
Transaction: SLG0
1. Click "New Entries"2. Object: ZTEST3. Object text: My Test Application4. Save
5. Create Sub-Object: - Sub-Object: BATCH - Text: Batch Processing
- Sub-Object: ONLINE - Text: Online Processing4. Log with Context (Additional Data)
DATA: lv_log_handle TYPE balloghndl, ls_log TYPE bal_s_log, ls_msg TYPE bal_s_msg.
" Create logls_log-object = 'ZORDERS'.ls_log-subobject = 'PROCESS'.ls_log-extnumber = 'Order Processing'.
CALL FUNCTION 'BAL_LOG_CREATE' EXPORTING i_s_log = ls_log IMPORTING e_log_handle = lv_log_handle.
" Message with contextls_msg-msgty = 'E'.ls_msg-msgid = 'ZORD'.ls_msg-msgno = '001'.ls_msg-msgv1 = '0000001234'. " Order number
" Context structure (for navigation)DATA: ls_context TYPE bal_s_cont.ls_context-tabname = 'VBAK'.ls_context-value = '0000001234'.
ls_msg-context-tabname = 'VBAK'.ls_msg-context-value = ls_context-value.
CALL FUNCTION 'BAL_LOG_MSG_ADD' EXPORTING i_log_handle = lv_log_handle i_s_msg = ls_msg.5. Read Logs from Database
DATA: lt_log_filter TYPE bal_s_lfil, lt_log_header TYPE balhdr_t, lt_log_handles TYPE bal_t_logh.
" Define filterlt_log_filter-object = VALUE #( ( sign = 'I' option = 'EQ' low = 'ZTEST' ) ).lt_log_filter-subobject = VALUE #( ( sign = 'I' option = 'EQ' low = 'BATCH' ) ).lt_log_filter-aldate = VALUE #( ( sign = 'I' option = 'GE' low = sy-datum - 7 ) ).
" Search logsCALL FUNCTION 'BAL_DB_SEARCH' EXPORTING i_s_log_filter = lt_log_filter IMPORTING e_t_log_header = lt_log_header EXCEPTIONS log_not_found = 1 no_filter_criteria = 2 OTHERS = 3.
IF sy-subrc = 0. WRITE: / 'Logs found:', lines( lt_log_header ).
" Load logs CALL FUNCTION 'BAL_DB_LOAD' EXPORTING i_t_log_header = lt_log_header IMPORTING e_t_log_handle = lt_log_handles EXCEPTIONS OTHERS = 1.
" Display CALL FUNCTION 'BAL_DSP_LOG_DISPLAY' EXPORTING i_t_log_handle = lt_log_handles EXCEPTIONS OTHERS = 1.ENDIF.6. Delete Log
DATA: lt_log_filter TYPE bal_s_lfil, lt_log_header TYPE balhdr_t.
" Find old logs (older than 30 days)lt_log_filter-object = VALUE #( ( sign = 'I' option = 'EQ' low = 'ZTEST' ) ).lt_log_filter-aldate = VALUE #( ( sign = 'I' option = 'LE' low = sy-datum - 30 ) ).
CALL FUNCTION 'BAL_DB_SEARCH' EXPORTING i_s_log_filter = lt_log_filter IMPORTING e_t_log_header = lt_log_header EXCEPTIONS OTHERS = 1.
" Delete logsIF lt_log_header IS NOT INITIAL. CALL FUNCTION 'BAL_DB_DELETE' EXPORTING i_t_logs_to_delete = lt_log_header EXCEPTIONS OTHERS = 1.
IF sy-subrc = 0. COMMIT WORK. WRITE: / 'Deleted:', lines( lt_log_header ), 'logs'. ENDIF.ENDIF.7. Callback for Detail Display
DATA: ls_msg TYPE bal_s_msg, ls_clbk TYPE bal_s_clbk.
" Define callbackls_clbk-userexitf = 'Z_SHOW_ORDER_DETAILS'. " Function modulels_clbk-userexitp = sy-repid. " Programls_clbk-userexitt = ' '.
ls_msg-msgty = 'E'.ls_msg-msgid = 'ZORD'.ls_msg-msgno = '001'.ls_msg-msgv1 = lv_vbeln.ls_msg-params-callback = ls_clbk.
CALL FUNCTION 'BAL_LOG_MSG_ADD' EXPORTING i_log_handle = lv_log_handle i_s_msg = ls_msg.
" Function module for callbackFUNCTION z_show_order_details.*" IMPORTING*" VALUE(I_S_MSG) TYPE BAL_S_MSG*"---------------------------------------------------------------------- " Display order SET PARAMETER ID 'AUN' FIELD i_s_msg-msgv1. CALL TRANSACTION 'VA03' AND SKIP FIRST SCREEN.ENDFUNCTION.8. Hierarchical Log
DATA: lv_log_handle TYPE balloghndl, lv_msg_handle TYPE balmsghndl, ls_msg TYPE bal_s_msg.
" Create main logCALL FUNCTION 'BAL_LOG_CREATE' EXPORTING i_s_log = ls_log IMPORTING e_log_handle = lv_log_handle.
" Parent messagels_msg-msgty = 'I'.ls_msg-msgid = 'ZLOG'.ls_msg-msgno = '000'.ls_msg-msgv1 = 'Processing Customer 1000'.
CALL FUNCTION 'BAL_LOG_MSG_ADD' EXPORTING i_log_handle = lv_log_handle i_s_msg = ls_msg IMPORTING e_msg_handle = lv_msg_handle. " Handle for parent
" Child messagesls_msg-msgv1 = ' Address updated'.CALL FUNCTION 'BAL_LOG_MSG_ADD' EXPORTING i_log_handle = lv_log_handle i_s_msg = ls_msg i_msg_handle_par = lv_msg_handle. " Parent handle
ls_msg-msgv1 = ' Contacts synchronized'.CALL FUNCTION 'BAL_LOG_MSG_ADD' EXPORTING i_log_handle = lv_log_handle i_s_msg = ls_msg i_msg_handle_par = lv_msg_handle.9. Log with Priority and Detail Level
DATA: ls_msg TYPE bal_s_msg.
" Detail levells_msg-detlevel = '1'. " 1-9, higher = more detaills_msg-probclass = '1'. " Problem class 1 = important, 4 = unimportant
" Filter on displayDATA: ls_profile TYPE bal_s_prof.
CALL FUNCTION 'BAL_DSP_PROFILE_STANDARD_GET' IMPORTING e_s_display_profile = ls_profile.
" Only important messages (problem class 1-2)ls_profile-mess_filter-probclass = VALUE #( ( sign = 'I' option = 'BT' low = '1' high = '2' )).
CALL FUNCTION 'BAL_DSP_LOG_DISPLAY' EXPORTING i_t_log_handle = lt_log_handles i_s_display_profile = ls_profile.10. Automatic Log on Exceptions
CLASS zcl_logged_processor DEFINITION. PUBLIC SECTION. METHODS: constructor IMPORTING io_log TYPE REF TO zcl_application_log.
METHODS: process IMPORTING it_data TYPE ty_data_tab RAISING zcx_processing_error.
PRIVATE SECTION. DATA: mo_log TYPE REF TO zcl_application_log.ENDCLASS.
CLASS zcl_logged_processor IMPLEMENTATION. METHOD constructor. mo_log = io_log. ENDMETHOD.
METHOD process. mo_log->add_info( |Processing { lines( it_data ) } entries| ).
LOOP AT it_data INTO DATA(ls_data). TRY. " Processing process_single( ls_data ). mo_log->add_success( |Entry { ls_data-id } processed| ).
CATCH cx_root INTO DATA(lx_error). mo_log->add_error( |Entry { ls_data-id }: { lx_error->get_text( ) }| ).
" Abort on critical error IF lx_error IS INSTANCE OF zcx_critical_error. mo_log->add_error( 'Critical error - aborting' ). mo_log->save( ). RAISE EXCEPTION TYPE zcx_processing_error EXPORTING previous = lx_error. ENDIF. ENDTRY. ENDLOOP.
mo_log->add_success( 'Processing completed' ). ENDMETHOD.ENDCLASS.11. Mass Logging (Performance)
DATA: lt_messages TYPE bal_t_msg, ls_msg TYPE bal_s_msg.
" Collect messages instead of adding individuallyLOOP AT lt_data INTO DATA(ls_data). ls_msg-msgty = 'S'. ls_msg-msgid = 'ZLOG'. ls_msg-msgno = '000'. ls_msg-msgv1 = |Record { ls_data-id } processed|. APPEND ls_msg TO lt_messages.ENDLOOP.
" Add all at onceCALL FUNCTION 'BAL_LOG_MSGS_ADD' EXPORTING i_log_handle = lv_log_handle i_t_msg = lt_messages EXCEPTIONS OTHERS = 1.
" Save onceCALL FUNCTION 'BAL_DB_SAVE' EXPORTING i_save_all = abap_true.12. Use Log in Job
REPORT zlog_in_job.
DATA: go_log TYPE REF TO zcl_application_log.
START-OF-SELECTION. " Initialize log go_log = NEW zcl_application_log( iv_object = 'ZJOB' iv_subobject = 'DAILY' iv_extnumber = |Job { sy-datum } { sy-uzeit }| ).
go_log->add_info( 'Job started' ).
TRY. " Processing perform_processing( ). go_log->add_success( 'Job completed successfully' ).
CATCH cx_root INTO DATA(lx_error). go_log->add_exception( lx_error ). go_log->add_error( 'Job ended with error' ). ENDTRY.
" Always save go_log->save( ).
END-OF-SELECTION.13. Call SLG1 Programmatically
" Log display like SLG1DATA: ls_display_profile TYPE bal_s_prof.
" Standard profileCALL FUNCTION 'BAL_DSP_PROFILE_STANDARD_GET' IMPORTING e_s_display_profile = ls_display_profile.
" Customize settingsls_display_profile-title = 'My Log Display'.ls_display_profile-tree_log = abap_true. " Tree display
" DisplayCALL FUNCTION 'BAL_DSP_LOG_DISPLAY' EXPORTING i_s_display_profile = ls_display_profile EXCEPTIONS OTHERS = 1.Important Function Modules
| Function Module | Description |
|---|---|
BAL_LOG_CREATE | Create log |
BAL_LOG_MSG_ADD | Add message |
BAL_DB_SAVE | Save to DB |
BAL_DB_SEARCH | Search logs |
BAL_DB_LOAD | Load logs |
BAL_DB_DELETE | Delete logs |
BAL_DSP_LOG_DISPLAY | Display logs |
Important Notes / Best Practice
- Maintain log objects in SLG0 (don’t hardcode).
- Use external number for easy search in SLG1.
- Don’t forget COMMIT WORK after BAL_DB_SAVE.
- Use hierarchy for clear structuring.
- Use context for navigation to documents.
- Implement callbacks for detail display.
- Use mass logging for performance with many messages.
- Regularly clean up old logs (performance).
- Use problem class and detail level for filtering.
- Combine with Background Jobs for batch logging.