Das Application Log (BAL) ist das Standard-Framework für persistente Protokollierung in SAP. Logs werden in der Datenbank gespeichert und können über Transaktion SLG1 angezeigt werden.
Grundkonzept
| Element | Beschreibung |
|---|---|
| Log Object | Gruppierung (z.B. Anwendung) - in SLG0 pflegen |
| Sub-Object | Unterkategorie des Log Objects |
| Log Handle | Eindeutige ID einer Log-Instanz |
| Message | Einzelne Protokollnachricht |
| SLG1 | Transaktion zur Log-Anzeige |
Nachrichtentypen
| Typ | Bedeutung | Icon |
|---|---|---|
| A | Abbruch | Rot |
| E | Fehler | Rot |
| W | Warnung | Gelb |
| I | Information | Blau |
| S | Erfolg | Grün |
Beispiele
1. Einfaches Log erstellen
DATA: lv_log_handle TYPE balloghndl, ls_log TYPE bal_s_log.
" Log-Headerls_log-object = 'ZTEST'. " Log-Objekt (aus SLG0)ls_log-subobject = 'PROCESS'. " Unter-Objektls_log-aldate = sy-datum.ls_log-altime = sy-uzeit.ls_log-aluser = sy-uname.ls_log-alprog = sy-repid.ls_log-extnumber = 'Meine Verarbeitung 001'.
" Log erstellenCALL 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.
" Nachricht hinzufügenDATA: ls_msg TYPE bal_s_msg.
ls_msg-msgty = 'S'.ls_msg-msgid = 'ZMYAPP'.ls_msg-msgno = '001'.ls_msg-msgv1 = 'Verarbeitung gestartet'.
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.
" Weitere Nachrichtenls_msg-msgty = 'I'.ls_msg-msgv1 = '100 Datensätze verarbeitet'.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 = 'Verarbeitung abgeschlossen'.CALL FUNCTION 'BAL_LOG_MSG_ADD' EXPORTING i_log_handle = lv_log_handle i_s_msg = ls_msg.
" Log speichernCALL 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 gespeichert'.ENDIF.2. OO-Ansatz mit 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.
" Freie Nachricht 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.
" VerwendungDATA(lo_log) = NEW zcl_application_log( iv_object = 'ZTEST' iv_subobject = 'BATCH' iv_extnumber = |Verarbeitung { sy-datum }|).
lo_log->add_success( 'Verarbeitung gestartet' ).lo_log->add_info( '500 Datensätze geladen' ).
TRY. " Verarbeitung... lo_log->add_success( 'Verarbeitung erfolgreich' ). CATCH cx_root INTO DATA(lx_error). lo_log->add_exception( lx_error ).ENDTRY.
IF lo_log->save( ). lo_log->display( ).ENDIF.3. Log-Objekt in SLG0 erstellen
Transaktion: SLG0
1. "Neue Einträge" klicken2. Objekt: ZTEST3. Objekttext: Meine Testanwendung4. Speichern
5. Unter-Objekt anlegen: - Unter-Objekt: BATCH - Text: Batch-Verarbeitung
- Unter-Objekt: ONLINE - Text: Online-Verarbeitung4. Log mit Kontext (zusätzliche Daten)
DATA: lv_log_handle TYPE balloghndl, ls_log TYPE bal_s_log, ls_msg TYPE bal_s_msg.
" Log erstellenls_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.
" Nachricht mit Kontextls_msg-msgty = 'E'.ls_msg-msgid = 'ZORD'.ls_msg-msgno = '001'.ls_msg-msgv1 = '0000001234'. " Bestellnummer
" Kontext-Struktur (für 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. Logs aus Datenbank lesen
DATA: lt_log_filter TYPE bal_s_lfil, lt_log_header TYPE balhdr_t, lt_log_handles TYPE bal_t_logh.
" Filter definierenlt_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 ) ).
" Logs suchenCALL 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: / 'Gefundene Logs:', lines( lt_log_header ).
" Logs laden CALL FUNCTION 'BAL_DB_LOAD' EXPORTING i_t_log_header = lt_log_header IMPORTING e_t_log_handle = lt_log_handles EXCEPTIONS OTHERS = 1.
" Anzeigen CALL FUNCTION 'BAL_DSP_LOG_DISPLAY' EXPORTING i_t_log_handle = lt_log_handles EXCEPTIONS OTHERS = 1.ENDIF.6. Log löschen
DATA: lt_log_filter TYPE bal_s_lfil, lt_log_header TYPE balhdr_t.
" Alte Logs finden (älter als 30 Tage)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.
" Logs löschenIF 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: / 'Gelöscht:', lines( lt_log_header ), 'Logs'. ENDIF.ENDIF.7. Callback für Detailanzeige
DATA: ls_msg TYPE bal_s_msg, ls_clbk TYPE bal_s_clbk.
" Callback definierenls_clbk-userexitf = 'Z_SHOW_ORDER_DETAILS'. " Funktionsbausteinls_clbk-userexitp = sy-repid. " Programmls_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.
" Funktionsbaustein für CallbackFUNCTION z_show_order_details.*" IMPORTING*" VALUE(I_S_MSG) TYPE BAL_S_MSG*"---------------------------------------------------------------------- " Bestellung anzeigen SET PARAMETER ID 'AUN' FIELD i_s_msg-msgv1. CALL TRANSACTION 'VA03' AND SKIP FIRST SCREEN.ENDFUNCTION.8. Hierarchisches Log
DATA: lv_log_handle TYPE balloghndl, lv_msg_handle TYPE balmsghndl, ls_msg TYPE bal_s_msg.
" Haupt-Log erstellenCALL FUNCTION 'BAL_LOG_CREATE' EXPORTING i_s_log = ls_log IMPORTING e_log_handle = lv_log_handle.
" Parent-Nachrichtls_msg-msgty = 'I'.ls_msg-msgid = 'ZLOG'.ls_msg-msgno = '000'.ls_msg-msgv1 = 'Verarbeitung Kunde 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 für Parent
" Kind-Nachrichtenls_msg-msgv1 = ' Adresse aktualisiert'.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 = ' Kontakte synchronisiert'.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 mit Priorität und Detailstufe
DATA: ls_msg TYPE bal_s_msg.
" Detailstufels_msg-detlevel = '1'. " 1-9, höher = mehr Detaills_msg-probclass = '1'. " Problemklasse 1 = wichtig, 4 = unwichtig
" Bei Anzeige filternDATA: ls_profile TYPE bal_s_prof.
CALL FUNCTION 'BAL_DSP_PROFILE_STANDARD_GET' IMPORTING e_s_display_profile = ls_profile.
" Nur wichtige Nachrichten (Problemklasse 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. Log automatisch bei 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( |Verarbeite { lines( it_data ) } Einträge| ).
LOOP AT it_data INTO DATA(ls_data). TRY. " Verarbeitung process_single( ls_data ). mo_log->add_success( |Eintrag { ls_data-id } verarbeitet| ).
CATCH cx_root INTO DATA(lx_error). mo_log->add_error( |Eintrag { ls_data-id }: { lx_error->get_text( ) }| ).
" Bei kritischem Fehler abbrechen IF lx_error IS INSTANCE OF zcx_critical_error. mo_log->add_error( 'Kritischer Fehler - Abbruch' ). mo_log->save( ). RAISE EXCEPTION TYPE zcx_processing_error EXPORTING previous = lx_error. ENDIF. ENDTRY. ENDLOOP.
mo_log->add_success( 'Verarbeitung abgeschlossen' ). ENDMETHOD.ENDCLASS.11. Massenprotokollierung (Performance)
DATA: lt_messages TYPE bal_t_msg, ls_msg TYPE bal_s_msg.
" Nachrichten sammeln statt einzeln hinzufügenLOOP AT lt_data INTO DATA(ls_data). ls_msg-msgty = 'S'. ls_msg-msgid = 'ZLOG'. ls_msg-msgno = '000'. ls_msg-msgv1 = |Datensatz { ls_data-id } verarbeitet|. APPEND ls_msg TO lt_messages.ENDLOOP.
" Alle auf einmal hinzufügenCALL FUNCTION 'BAL_LOG_MSGS_ADD' EXPORTING i_log_handle = lv_log_handle i_t_msg = lt_messages EXCEPTIONS OTHERS = 1.
" Einmal speichernCALL FUNCTION 'BAL_DB_SAVE' EXPORTING i_save_all = abap_true.12. Log in Job verwenden
REPORT zlog_in_job.
DATA: go_log TYPE REF TO zcl_application_log.
START-OF-SELECTION. " Log initialisieren go_log = NEW zcl_application_log( iv_object = 'ZJOB' iv_subobject = 'DAILY' iv_extnumber = |Job { sy-datum } { sy-uzeit }| ).
go_log->add_info( 'Job gestartet' ).
TRY. " Verarbeitung perform_processing( ). go_log->add_success( 'Job erfolgreich beendet' ).
CATCH cx_root INTO DATA(lx_error). go_log->add_exception( lx_error ). go_log->add_error( 'Job mit Fehler beendet' ). ENDTRY.
" Immer speichern go_log->save( ).
END-OF-SELECTION.13. SLG1 programmatisch aufrufen
" Log-Anzeige wie SLG1DATA: ls_display_profile TYPE bal_s_prof.
" Standard-ProfilCALL FUNCTION 'BAL_DSP_PROFILE_STANDARD_GET' IMPORTING e_s_display_profile = ls_display_profile.
" Einstellungen anpassenls_display_profile-title = 'Meine Log-Anzeige'.ls_display_profile-tree_log = abap_true. " Baumdarstellung
" AnzeigenCALL FUNCTION 'BAL_DSP_LOG_DISPLAY' EXPORTING i_s_display_profile = ls_display_profile EXCEPTIONS OTHERS = 1.Wichtige Funktionsbausteine
| Funktionsbaustein | Beschreibung |
|---|---|
BAL_LOG_CREATE | Log erstellen |
BAL_LOG_MSG_ADD | Nachricht hinzufügen |
BAL_DB_SAVE | In DB speichern |
BAL_DB_SEARCH | Logs suchen |
BAL_DB_LOAD | Logs laden |
BAL_DB_DELETE | Logs löschen |
BAL_DSP_LOG_DISPLAY | Logs anzeigen |
Wichtige Hinweise / Best Practice
- Log-Objekte in SLG0 pflegen (nicht hardcoden).
- Externe Nummer für einfache Suche in SLG1.
- COMMIT WORK nach BAL_DB_SAVE nicht vergessen.
- Hierarchie für übersichtliche Strukturierung nutzen.
- Kontext für Navigation zu Belegen.
- Callbacks für Detail-Anzeige implementieren.
- Massenprotokollierung für Performance bei vielen Nachrichten.
- Alte Logs regelmäßig bereinigen (Performance).
- Problemklasse und Detailstufe für Filterung nutzen.
- Kombinieren Sie mit Background Jobs für Batch-Protokollierung.