L’Application Log (BAL) est le framework standard pour la journalisation persistante dans SAP. Les logs sont stockes dans la base de donnees et peuvent etre affiches via la transaction SLG1.
Concept de base
| Element | Description |
|---|---|
| Log Object | Regroupement (par ex. application) - a maintenir dans SLG0 |
| Sub-Object | Sous-categorie du Log Object |
| Log Handle | ID unique d’une instance de log |
| Message | Message de journal individuel |
| SLG1 | Transaction pour l’affichage des logs |
Types de messages
| Type | Signification | Icone |
|---|---|---|
| A | Abandon | Rouge |
| E | Erreur | Rouge |
| W | Avertissement | Jaune |
| I | Information | Bleu |
| S | Succes | Vert |
Exemples
1. Creer un log simple
DATA: lv_log_handle TYPE balloghndl, ls_log TYPE bal_s_log.
" En-tete du logls_log-object = 'ZTEST'. " Objet de log (depuis SLG0)ls_log-subobject = 'PROCESS'. " Sous-objetls_log-aldate = sy-datum.ls_log-altime = sy-uzeit.ls_log-aluser = sy-uname.ls_log-alprog = sy-repid.ls_log-extnumber = 'Mon traitement 001'.
" Creer le 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.
" Ajouter un messageDATA: ls_msg TYPE bal_s_msg.
ls_msg-msgty = 'S'.ls_msg-msgid = 'ZMYAPP'.ls_msg-msgno = '001'.ls_msg-msgv1 = 'Traitement demarre'.
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.
" Autres messagesls_msg-msgty = 'I'.ls_msg-msgv1 = '100 enregistrements traites'.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 = 'Traitement termine'.CALL FUNCTION 'BAL_LOG_MSG_ADD" EXPORTING i_log_handle = lv_log_handle i_s_msg = ls_msg.
" Sauvegarder le 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 sauvegarde'.ENDIF.2. Approche OO avec 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.
" Message libre 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.
" UtilisationDATA(lo_log) = NEW zcl_application_log( iv_object = 'ZTEST" iv_subobject = 'BATCH" iv_extnumber = |Traitement { sy-datum }|).
lo_log->add_success( 'Traitement demarre' ).lo_log->add_info( '500 enregistrements charges' ).
TRY. " Traitement... lo_log->add_success( 'Traitement reussi' ). CATCH cx_root INTO DATA(lx_error). lo_log->add_exception( lx_error ).ENDTRY.
IF lo_log->save( ). lo_log->display( ).ENDIF.3. Creer un objet de log dans SLG0
Transaction : SLG0
1. Cliquer sur "Nouvelles entrees"2. Objet : ZTEST3. Texte objet : Mon application de test4. Sauvegarder
5. Creer un sous-objet : - Sous-objet : BATCH - Texte : Traitement batch
- Sous-objet : ONLINE - Texte : Traitement en ligne4. Log avec contexte (donnees supplementaires)
DATA: lv_log_handle TYPE balloghndl, ls_log TYPE bal_s_log, ls_msg TYPE bal_s_msg.
" Creer le 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 avec contextels_msg-msgty = 'E'.ls_msg-msgid = 'ZORD'.ls_msg-msgno = '001'.ls_msg-msgv1 = '0000001234'. " Numero de commande
" Structure de contexte (pour la 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. Lire les logs depuis la base de donnees
DATA: lt_log_filter TYPE bal_s_lfil, lt_log_header TYPE balhdr_t, lt_log_handles TYPE bal_t_logh.
" Definir le filtrelt_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 ) ).
" Rechercher les 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 trouves:', lines( lt_log_header ).
" Charger les 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.
" Afficher CALL FUNCTION 'BAL_DSP_LOG_DISPLAY" EXPORTING i_t_log_handle = lt_log_handles EXCEPTIONS OTHERS = 1.ENDIF.6. Supprimer un log
DATA: lt_log_filter TYPE bal_s_lfil, lt_log_header TYPE balhdr_t.
" Trouver les anciens logs (plus de 30 jours)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.
" Supprimer les 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: / 'Supprimes:', lines( lt_log_header ), 'logs'. ENDIF.ENDIF.7. Callback pour l’affichage des details
DATA: ls_msg TYPE bal_s_msg, ls_clbk TYPE bal_s_clbk.
" Definir le callbackls_clbk-userexitf = 'Z_SHOW_ORDER_DETAILS'. " Module fonctionls_clbk-userexitp = sy-repid. " Programmels_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.
" Module fonction pour le callbackFUNCTION z_show_order_details.*" IMPORTING*" VALUE(I_S_MSG) TYPE BAL_S_MSG*"---------------------------------------------------------------------- " Afficher la commande SET PARAMETER ID 'AUN' FIELD i_s_msg-msgv1. CALL TRANSACTION 'VA03' AND SKIP FIRST SCREEN.ENDFUNCTION.8. Log hierarchique
DATA: lv_log_handle TYPE balloghndl, lv_msg_handle TYPE balmsghndl, ls_msg TYPE bal_s_msg.
" Creer le log principalCALL FUNCTION 'BAL_LOG_CREATE" EXPORTING i_s_log = ls_log IMPORTING e_log_handle = lv_log_handle.
" Message parentls_msg-msgty = 'I'.ls_msg-msgid = 'ZLOG'.ls_msg-msgno = '000'.ls_msg-msgv1 = 'Traitement Client 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 pour le parent
" Messages enfantsls_msg-msgv1 = ' Adresse mise a jour'.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. " Handle parent
ls_msg-msgv1 = ' Contacts synchronises'.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 avec priorite et niveau de detail
DATA: ls_msg TYPE bal_s_msg.
" Niveau de detaills_msg-detlevel = '1'. " 1-9, plus eleve = plus de detaills_msg-probclass = '1'. " Classe de probleme 1 = important, 4 = sans importance
" Filtrer a l'affichageDATA: ls_profile TYPE bal_s_prof.
CALL FUNCTION 'BAL_DSP_PROFILE_STANDARD_GET" IMPORTING e_s_display_profile = ls_profile.
" Seulement les messages importants (classe de probleme 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 automatique pour les 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( |Traitement de { lines( it_data ) } entrees| ).
LOOP AT it_data INTO DATA(ls_data). TRY. " Traitement process_single( ls_data ). mo_log->add_success( |Entree { ls_data-id } traitee| ).
CATCH cx_root INTO DATA(lx_error). mo_log->add_error( |Entree { ls_data-id }: { lx_error->get_text( ) }| ).
" Abandonner en cas d'erreur critique IF lx_error IS INSTANCE OF zcx_critical_error. mo_log->add_error( 'Erreur critique - Abandon' ). mo_log->save( ). RAISE EXCEPTION TYPE zcx_processing_error EXPORTING previous = lx_error. ENDIF. ENDTRY. ENDLOOP.
mo_log->add_success( 'Traitement termine' ). ENDMETHOD.ENDCLASS.11. Journalisation en masse (Performance)
DATA: lt_messages TYPE bal_t_msg, ls_msg TYPE bal_s_msg.
" Collecter les messages au lieu de les ajouter un par unLOOP AT lt_data INTO DATA(ls_data). ls_msg-msgty = 'S'. ls_msg-msgid = 'ZLOG'. ls_msg-msgno = '000'. ls_msg-msgv1 = |Enregistrement { ls_data-id } traite|. APPEND ls_msg TO lt_messages.ENDLOOP.
" Ajouter tous en une foisCALL FUNCTION 'BAL_LOG_MSGS_ADD" EXPORTING i_log_handle = lv_log_handle i_t_msg = lt_messages EXCEPTIONS OTHERS = 1.
" Sauvegarder une seule foisCALL FUNCTION 'BAL_DB_SAVE" EXPORTING i_save_all = abap_true.12. Utiliser le log dans un job
REPORT zlog_in_job.
DATA: go_log TYPE REF TO zcl_application_log.
START-OF-SELECTION. " Initialiser le 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 demarre' ).
TRY. " Traitement perform_processing( ). go_log->add_success( 'Job termine avec succes' ).
CATCH cx_root INTO DATA(lx_error). go_log->add_exception( lx_error ). go_log->add_error( 'Job termine avec erreur' ). ENDTRY.
" Toujours sauvegarder go_log->save( ).
END-OF-SELECTION.13. Appeler SLG1 par programmation
" Affichage de log comme SLG1DATA: ls_display_profile TYPE bal_s_prof.
" Profil standardCALL FUNCTION 'BAL_DSP_PROFILE_STANDARD_GET" IMPORTING e_s_display_profile = ls_display_profile.
" Personnaliser les parametresls_display_profile-title = 'Mon affichage de log'.ls_display_profile-tree_log = abap_true. " Representation en arbre
" AfficherCALL FUNCTION 'BAL_DSP_LOG_DISPLAY" EXPORTING i_s_display_profile = ls_display_profile EXCEPTIONS OTHERS = 1.Modules fonction importants
| Module fonction | Description |
|---|---|
BAL_LOG_CREATE | Creer un log |
BAL_LOG_MSG_ADD | Ajouter un message |
BAL_DB_SAVE | Sauvegarder dans la BD |
BAL_DB_SEARCH | Rechercher des logs |
BAL_DB_LOAD | Charger des logs |
BAL_DB_DELETE | Supprimer des logs |
BAL_DSP_LOG_DISPLAY | Afficher des logs |
Remarques importantes / Bonnes pratiques
- Objets de log a maintenir dans SLG0 (ne pas coder en dur).
- Numero externe pour une recherche facile dans SLG1.
- COMMIT WORK ne pas oublier apres BAL_DB_SAVE.
- Hierarchie a utiliser pour une structuration claire.
- Contexte pour la navigation vers les documents.
- Callbacks a implementer pour l’affichage des details.
- Journalisation en masse pour la performance avec beaucoup de messages.
- Nettoyer regulierement les anciens logs (performance).
- Classe de probleme et niveau de detail a utiliser pour le filtrage.
- Combiner avec Background Jobs pour la journalisation batch.