ABAP Application Logging: BAL, CL_BAL_LOG, SLG1

Kategorie
ABAP-Statements
Veröffentlicht
Autor
Johannes

El Application Log (BAL) es el framework estándar para registro persistente en SAP. Los logs se almacenan en la base de datos y pueden visualizarse mediante la transacción SLG1.

Concepto básico

ElementoDescripción
Log ObjectAgrupación (p.ej. aplicación) - mantener en SLG0
Sub-ObjectSubcategoría del Log Object
Log HandleID único de una instancia de log
MessageMensaje individual del protocolo
SLG1Transacción para visualización de logs

Tipos de mensaje

TipoSignificadoIcono
AAbortoRojo
EErrorRojo
WAdvertenciaAmarillo
IInformaciónAzul
SÉxitoVerde

Ejemplos

1. Crear log simple

DATA: lv_log_handle TYPE balloghndl,
ls_log TYPE bal_s_log.
" Cabecera del log
ls_log-object = 'ZTEST'. " Objeto de log (desde SLG0)
ls_log-subobject = 'PROCESS'. " Subobjeto
ls_log-aldate = sy-datum.
ls_log-altime = sy-uzeit.
ls_log-aluser = sy-uname.
ls_log-alprog = sy-repid.
ls_log-extnumber = 'Mi procesamiento 001'.
" Crear log
CALL 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.
" Añadir mensaje
DATA: ls_msg TYPE bal_s_msg.
ls_msg-msgty = 'S'.
ls_msg-msgid = 'ZMYAPP'.
ls_msg-msgno = '001'.
ls_msg-msgv1 = 'Procesamiento iniciado'.
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.
" Más mensajes
ls_msg-msgty = 'I'.
ls_msg-msgv1 = '100 registros procesados'.
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 = 'Procesamiento completado'.
CALL FUNCTION 'BAL_LOG_MSG_ADD'
EXPORTING i_log_handle = lv_log_handle i_s_msg = ls_msg.
" Guardar log
CALL 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 guardado'.
ENDIF.

2. Enfoque OO con 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.
" Mensaje 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.
" Uso
DATA(lo_log) = NEW zcl_application_log(
iv_object = 'ZTEST'
iv_subobject = 'BATCH'
iv_extnumber = |Procesamiento { sy-datum }|
).
lo_log->add_success( 'Procesamiento iniciado' ).
lo_log->add_info( '500 registros cargados' ).
TRY.
" Procesamiento...
lo_log->add_success( 'Procesamiento exitoso' ).
CATCH cx_root INTO DATA(lx_error).
lo_log->add_exception( lx_error ).
ENDTRY.
IF lo_log->save( ).
lo_log->display( ).
ENDIF.

3. Crear objeto de log en SLG0

Transacción: SLG0
1. Clic en "Nuevas entradas"
2. Objeto: ZTEST
3. Texto del objeto: Mi aplicación de prueba
4. Guardar
5. Crear subobjeto:
- Subobjeto: BATCH
- Texto: Procesamiento batch
- Subobjeto: ONLINE
- Texto: Procesamiento online

4. Log con contexto (datos adicionales)

DATA: lv_log_handle TYPE balloghndl,
ls_log TYPE bal_s_log,
ls_msg TYPE bal_s_msg.
" Crear log
ls_log-object = 'ZORDERS'.
ls_log-subobject = 'PROCESS'.
ls_log-extnumber = 'Procesamiento de pedidos'.
CALL FUNCTION 'BAL_LOG_CREATE'
EXPORTING i_s_log = ls_log
IMPORTING e_log_handle = lv_log_handle.
" Mensaje con contexto
ls_msg-msgty = 'E'.
ls_msg-msgid = 'ZORD'.
ls_msg-msgno = '001'.
ls_msg-msgv1 = '0000001234'. " Número de pedido
" Estructura de contexto (para navegación)
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. Leer logs de la base de datos

DATA: lt_log_filter TYPE bal_s_lfil,
lt_log_header TYPE balhdr_t,
lt_log_handles TYPE bal_t_logh.
" Definir filtro
lt_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 ) ).
" Buscar logs
CALL 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 encontrados:', lines( lt_log_header ).
" Cargar 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.
" Mostrar
CALL FUNCTION 'BAL_DSP_LOG_DISPLAY'
EXPORTING
i_t_log_handle = lt_log_handles
EXCEPTIONS
OTHERS = 1.
ENDIF.

6. Eliminar logs

DATA: lt_log_filter TYPE bal_s_lfil,
lt_log_header TYPE balhdr_t.
" Encontrar logs antiguos (más de 30 días)
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.
" Eliminar logs
IF 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: / 'Eliminados:', lines( lt_log_header ), 'logs'.
ENDIF.
ENDIF.

Módulos de función importantes

Módulo de funciónDescripción
BAL_LOG_CREATECrear log
BAL_LOG_MSG_ADDAñadir mensaje
BAL_DB_SAVEGuardar en BD
BAL_DB_SEARCHBuscar logs
BAL_DB_LOADCargar logs
BAL_DB_DELETEEliminar logs
BAL_DSP_LOG_DISPLAYMostrar logs

Notas importantes / Mejores prácticas

  • Objetos de log mantener en SLG0 (no hardcodear).
  • Número externo para búsqueda fácil en SLG1.
  • COMMIT WORK no olvidar tras BAL_DB_SAVE.
  • Jerarquía usar para estructuración clara.
  • Contexto para navegación a documentos.
  • Callbacks implementar para visualización de detalles.
  • Registro masivo para rendimiento con muchos mensajes.
  • Logs antiguos limpiar regularmente (rendimiento).
  • Clase de problema y nivel de detalle usar para filtrado.
  • Combinar con Background Jobs para protocolo batch.