
BTP - Application Job (Log)
Wie erzeuge ich im Application Job ein Joblog, sodass der User wichtige Informationen zum Job erhält? In diesem Artikel schauen wir uns das Thema näher an.
Inhaltsverzeichnis
Die Ausgabe von Meldungen für einen Job ist wichtig, da ein Debugging im ABAP Environment nicht möglich ist und wir zu bestimmten Zuständen im Jobinformationen benötigen, vor allem wenn dieser bei der Verarbeitung abbricht. In diesem Artikel schauen wir uns die Besonderheiten an und wie wir ein Protokoll an den Job hängen.
Einleitung
Für die Erzeugung von Nachrichten am Job benötigen wir das Application Log, dieses ist von On-Premise über die Transaktion SLG0 und SLG1 bekannt. Im ABAP Environment funktioniert die Erzeugung etwas anders als wir es bisher von On-Premise gewohnt sind. Letzte Woche hatten wir den Artikel zum Logging im ABAP Cloud Umfeld veröffentlicht, dort kannst du noch einmal die Gemeinsamkeiten und Unterschiede nachlesen und weitere Informationen bekommen, auf die wir in diesem Artikel nicht mehr im Detail eingehen werden.
Application Log
In diesem Abschnitt erweitern wir den Job um die Ausgabe von Meldungen und ermöglichen Einblicke in den Joblauf, vor allem wenn es zu Problemen kommt.
Log Objekt
Zuerst einmal müssen wir ein Application Log Objekt und Unterobjekt erzeugen, um damit Meldungen am Job sichern zu können. Über die ABAP Development Tools legen wir es im Paket des Jobs an:
Meldungen
Im nächsten Schritt wollen wir das Application Log im Job verwenden, dazu erweitern wir die ausführende Klasse ZCL_BS_DEMO_JOB_ADT_EXE die wir in diesem Artikel angelegt haben. Dazu definieren wir eine neue Methode, die einige Meldungen erstellen und Speichern soll.
METHODS log_some_messages
IMPORTING id_severity TYPE cl_bali_free_text_setter=>ty_severity
RAISING cx_bali_runtime
cx_uuid_error.
In der Methode erzeugen wir ein mit dem Demo-Log-Objekt, fügen einige Freitext Meldungen hinzu und speichern das Log auf der Datenbank. Die erste Meldung wird durch den Übergabeparameter bestimmt. Grundsätzlich benötigt man die Variable LO_FREE nicht und man könnte den Aufruf verketten, der Übersichtlichkeit halber, haben wir die Aufrufe im Beispiel getrennt.
METHOD log_some_messages.
DATA lo_free TYPE REF TO if_bali_free_text_setter.
DATA(lo_log) = cl_bali_log=>create( ).
DATA(lo_header) = cl_bali_header_setter=>create( object = 'ZBS_DEMO_JOB_LOG'
subobject = 'JOB'
external_id = cl_system_uuid=>create_uuid_c32_static( ) ).
lo_log->set_header( lo_header ).
lo_free = cl_bali_free_text_setter=>create( severity = id_severity
text = 'This message is free' ).
lo_log->add_item( lo_free ).
lo_free = cl_bali_free_text_setter=>create( severity = if_bali_constants=>c_severity_warning
text = 'This is a warning' ).
lo_log->add_item( lo_free ).
lo_free = cl_bali_free_text_setter=>create( severity = if_bali_constants=>c_severity_status
text = 'This is a success' ).
lo_log->add_item( lo_free ).
cl_bali_log_db=>get_instance( )->save_log( log = lo_log
assign_to_current_appl_job = abap_true ).
ENDMETHOD.
Hinweis: Entscheidend ist vor allem die Einstellung beim Speichern des Logs, hier muss das Flag ASSIGN_TO_CURRENT_APPL_JOB auf ABAP_TRUE gesetzt werden, damit das Log mit dem laufenden Job gespeichert wird.
Ausführung
Planen wir nun einmal den Job im System ein und lassen ihn laufen. Im Bereich "Log" taucht nun eine entsprechende Identifikation des Joblaufs auf, diese dient auch als Navigation in die Logs.
Wenn du auf den Button klickst, gelangst du in das entsprechende Application Log und hast hier noch die weiteren Möglichkeiten auf Meldungstexte und Schwere der Meldungen zu filtern.
Der Gesamtstatus des Jobs wird durch die höchste Schwere in den Nachrichten bestimmt. Dadurch, dass wir eine Fehlermeldung erzeugt haben, ist der Job rot.
Besonderheit
Was passiert eigentlich, wenn wir beim Jobablauf mehrere Logging Objekte erzeugen und Speichern? Dazu rufen wir die Methode LOG_SOME_MESSAGES zwei Mal auf, einmal mit "Warnung" und einmal mit der "Fehler". Planen wir nun den Job ein, sehen wir eine Veränderung im Jobstatus.
Der Indikator verrät uns, dass zwei Logs am Job gespeichert wurden. Bei einem Klick auf den Status erhalten wir die Auswahl in eines der beiden Logs abzuspringen. Jedes Log hat eine entsprechende Markierung für den Schweregrad, sodass wir die Fehler sofort identifizieren können. Nach dem Absprung sehen wir die gleiche Ansicht wie im Bild oben.
Vollständiges Beispiel
Zum Abschluss des Artikels noch einmal die gesamte Jobklasse zum Nachvollziehen der Anpassungen, die wir in diesem Artikel durchgeführt haben.
CLASS zcl_bs_demo_job_adt_exe DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_apj_dt_exec_object.
INTERFACES if_apj_rt_exec_object.
PRIVATE SECTION.
METHODS log_some_messages
IMPORTING id_severity TYPE cl_bali_free_text_setter=>ty_severity
RAISING cx_bali_runtime
cx_uuid_error.
ENDCLASS.
CLASS zcl_bs_demo_job_adt_exe IMPLEMENTATION.
METHOD if_apj_dt_exec_object~get_parameters.
et_parameter_def = VALUE #( datatype = 'C'
changeable_ind = abap_true
( selname = 'TEXT'
kind = if_apj_dt_exec_object=>parameter
param_text = 'Free text'
length = 50
lowercase_ind = abap_true
mandatory_ind = abap_true )
( selname = 'COUNTRY'
kind = if_apj_dt_exec_object=>select_option
param_text = 'Country'
length = 3 )
( selname = 'R_TEXT'
kind = if_apj_dt_exec_object=>parameter
param_text = 'Text'
length = 1
radio_group_ind = abap_true
radio_group_id = 'R1' )
( selname = 'R_LAND'
kind = if_apj_dt_exec_object=>parameter
param_text = 'Country'
length = 1
radio_group_ind = abap_true
radio_group_id = 'R1' )
( selname = 'TEST'
kind = if_apj_dt_exec_object=>parameter
param_text = 'Test'
length = 1
checkbox_ind = abap_true ) ).
et_parameter_val = VALUE #( sign = 'I'
option = 'EQ'
( selname = 'TEST' low = abap_true )
( selname = 'R_TEXT' low = abap_false )
( selname = 'R_LAND' low = abap_true ) ).
ENDMETHOD.
METHOD if_apj_rt_exec_object~execute.
DATA ld_text TYPE c LENGTH 50.
DATA lt_r_country TYPE RANGE OF I_CountryText-Country.
DATA ld_radio_text TYPE abap_boolean.
DATA ld_radio_country TYPE abap_boolean.
DATA ld_test TYPE abap_boolean.
LOOP AT it_parameters INTO DATA(ls_parameter).
CASE ls_parameter-selname.
WHEN 'TEXT'.
ld_text = ls_parameter-low.
WHEN 'COUNTRY'.
INSERT CORRESPONDING #( ls_parameter ) INTO TABLE lt_r_country.
WHEN 'R_TEXT'.
ld_radio_text = ls_parameter-low.
WHEN 'R_LAND'.
ld_radio_country = ls_parameter-low.
WHEN 'TEST'.
ld_test = ls_parameter-low.
ENDCASE.
ENDLOOP.
DATA(ls_database) = VALUE zbs_dmo_jtrack( identifier = cl_system_uuid=>create_uuid_x16_static( )
rdate = cl_abap_context_info=>get_system_date( )
rtime = cl_abap_context_info=>get_system_time( )
test = ld_test ).
CASE abap_true.
WHEN ld_radio_text.
ls_database-content = ld_text.
WHEN ld_radio_country.
SELECT FROM I_CountryText
FIELDS CountryName
WHERE Country IN @lt_r_country
AND Language = @sy-langu
INTO TABLE @DATA(lt_names).
ls_database-content = concat_lines_of( table = lt_names sep = `, ` ).
ENDCASE.
INSERT zbs_dmo_jtrack FROM @ls_database.
COMMIT WORK.
log_some_messages( if_bali_constants=>c_severity_warning ).
log_some_messages( if_bali_constants=>c_severity_error ).
ENDMETHOD.
METHOD log_some_messages.
DATA lo_free TYPE REF TO if_bali_free_text_setter.
DATA(lo_log) = cl_bali_log=>create( ).
DATA(lo_header) = cl_bali_header_setter=>create( object = 'ZBS_DEMO_JOB_LOG'
subobject = 'JOB'
external_id = cl_system_uuid=>create_uuid_c32_static( ) ).
lo_log->set_header( lo_header ).
lo_free = cl_bali_free_text_setter=>create( severity = id_severity
text = 'This message is free' ).
lo_log->add_item( lo_free ).
lo_free = cl_bali_free_text_setter=>create( severity = if_bali_constants=>c_severity_warning
text = 'This is a warning' ).
lo_log->add_item( lo_free ).
lo_free = cl_bali_free_text_setter=>create( severity = if_bali_constants=>c_severity_status
text = 'This is a success' ).
lo_log->add_item( lo_free ).
cl_bali_log_db=>get_instance( )->save_log( log = lo_log
assign_to_current_appl_job = abap_true ).
ENDMETHOD.
ENDCLASS.
Fazit
Mit den Application Logs hast du die Möglichkeit Meldungen im Job nach außen zu geben. Dabei bist du nicht beschränkt auf ein Log, sondern kannst so viele Logs wie möglich an den Job hängen. Du solltest allerdings dabei beachten, dass die einzige Identifikation dann die ID des Logs ist und eine übergreifende Suche nicht möglich ist.