抬头;

**initialize logger. It should be always on the top of the FUNCTION.
/afl/log_init.
**optional, you can specify at most 3 fields for search.
/afl/set_custom_fields customer-is_head-kunnr customer-is_head-name1 customer-is_head-sortl.
结尾:

**optional, you can save a status code and message text for search.
/afl/set_status es_return-type es_return-mess.
**save logs. It should be always on the bottom of the FUNCTION.
/afl/save.
源代码:

*&---------------------------------------------------------------------* *& Include ZAFL_MACROS *&---------------------------------------------------------------------* DEFINE /afl/log_init. DATA: /afl/comp_tab TYPE cl_abap_structdescr=>component_table, /afl/comp_wa LIKE LINE OF /afl/comp_tab. DATA: /afl/struct_type TYPE REF TO cl_abap_structdescr, "Structure /afl/parameter_data TYPE REF TO data. DATA: /afl/table_structure_type TYPE REF TO cl_abap_structdescr, /afl/table_type TYPE REF TO cl_abap_tabledescr. DATA: true_fieldname TYPE string. FIELD-SYMBOLS: </afl/parameter_data> TYPE any, </afl/parameter_data_field> TYPE any, </afl/parameter> TYPE any. DATA: /afl/callstack TYPE abap_callstack. DATA: /afl/log TYPE zafl_log. GET TIME. CALL FUNCTION 'SYSTEM_CALLSTACK' IMPORTING callstack = /afl/callstack. DATA(/afl/func_name) = VALUE #( /afl/callstack[ 1 ]-blockname OPTIONAL ). SELECT SINGLE * FROM zafl_config WHERE fname = @/afl/func_name AND enabled = 'X' INTO @DATA(/afl/config). IF sy-subrc = 0. * SELECT funcname, paramtype, pposition, parameter, structure * FROM fupararef * WHERE funcname = @/afl/func_name * INTO TABLE @DATA(/afl/parameters_tab). SELECT funcname, paramtype, pposition, parameter, structure FROM fupararef WHERE funcname = @/afl/func_name INTO TABLE @DATA(/vita/parameters_tab). IF sy-subrc = 0. * SORT /afl/parameters_tab BY paramtype pposition. SORT /vita/parameters_tab BY paramtype pposition. FIELD-SYMBOLS: </alf/parameters> LIKE LINE OF /vita/parameters_tab,"/vita/parameters_tab,/afl/parameters_tab, </alf/comp> LIKE LINE OF /afl/comp_tab. "处理行类型 BY ocx DATA: /alf/rowtype TYPE dd40l-rowtype. LOOP AT /vita/parameters_tab ASSIGNING </alf/parameters> WHERE paramtype = 'T'. CLEAR: /alf/rowtype. SELECT SINGLE rowtype INTO /alf/rowtype FROM dd40l WHERE typename = </alf/parameters>-structure AND as4local = 'A'. IF sy-subrc EQ 0 AND /alf/rowtype IS NOT INITIAL. </alf/parameters>-structure = /alf/rowtype. ENDIF. ENDLOOP. "<<<<<<<<<< END BY ocx @14.04.2021 IF /afl/config-import = abap_true. /afl/log_get_json 'I' /afl/log-import. ENDIF. IF /afl/config-change = abap_true. /afl/log_get_json 'C' /afl/log-change_in. ENDIF. IF /afl/config-table_in = abap_true. /afl/log_get_table_json /afl/log-table_in. ENDIF. DATA: /afl/start_time TYPE tzntstmpl. TRY. /afl/log-guid = cl_system_uuid=>create_uuid_x16_static( ). CATCH cx_uuid_error INTO DATA(/afl/oref). ENDTRY. GET TIME STAMP FIELD /afl/start_time. GET TIME STAMP FIELD /afl/log-timestamp. /afl/log = VALUE #( BASE /afl/log fname = /afl/func_name uname = sy-uname ). ENDIF. ENDIF. END-OF-DEFINITION. DEFINE /afl/log_get_json. CLEAR /afl/comp_tab. LOOP AT /vita/parameters_tab ASSIGNING </alf/parameters> WHERE paramtype = &1. /afl/comp_wa-name = </alf/parameters>-parameter. /afl/comp_wa-type ?= cl_abap_datadescr=>describe_by_name( </alf/parameters>-structure ). APPEND /afl/comp_wa TO /afl/comp_tab. ENDLOOP. IF /afl/comp_tab IS NOT INITIAL. /afl/struct_type = cl_abap_structdescr=>create( /afl/comp_tab ). CREATE DATA /afl/parameter_data TYPE HANDLE /afl/struct_type. ASSIGN /afl/parameter_data->* TO </afl/parameter_data>. LOOP AT /afl/comp_tab ASSIGNING </alf/comp>. ASSIGN (</alf/comp>-name) TO </afl/parameter>. ASSIGN COMPONENT </alf/comp>-name OF STRUCTURE </afl/parameter_data> TO </afl/parameter_data_field>. </afl/parameter_data_field> = </afl/parameter>. ENDLOOP. &2 = /ui2/cl_json=>serialize( data = </afl/parameter_data> ). ENDIF. END-OF-DEFINITION. DEFINE /afl/set_custom_fields. /afl/log = VALUE #( BASE /afl/log cust_field1 = &1 cust_field2 = &2 cust_field3 = &3 ). END-OF-DEFINITION. DEFINE /afl/set_status . /afl/log = VALUE #( BASE /afl/log status = &1 message = &2 ). END-OF-DEFINITION. DEFINE /afl/save . IF /afl/log-guid IS NOT INITIAL. DATA: /afl/end_time TYPE tzntstmpl. IF /afl/config-export = abap_true. /afl/log_get_json 'E' /afl/log-export. ENDIF. IF /afl/config-table_out = abap_true. /afl/log_get_table_json /afl/log-table_out. ENDIF. IF /afl/config-change = abap_true. /afl/log_get_json 'C' /afl/log-change_out. ENDIF. GET TIME. GET TIME STAMP FIELD /afl/end_time. /afl/log-time_cost = cl_abap_tstmp=>subtract( tstmp1 = /afl/end_time tstmp2 = /afl/start_time ). MODIFY zafl_log FROM @/afl/log. IF /afl/config-no_commit = abap_false. COMMIT WORK. ENDIF. ENDIF. END-OF-DEFINITION. DEFINE /afl/log_get_table_json. CLEAR /afl/comp_tab. LOOP AT /vita/parameters_tab ASSIGNING </alf/parameters> WHERE paramtype = 'T'. /afl/comp_wa-name = </alf/parameters>-parameter. /afl/table_structure_type = CAST cl_abap_structdescr( cl_abap_datadescr=>describe_by_name( </alf/parameters>-structure ) ). /afl/table_type = CAST cl_abap_tabledescr( cl_abap_tabledescr=>create( /afl/table_structure_type ) ). /afl/comp_wa-type ?= /afl/table_type. APPEND /afl/comp_wa TO /afl/comp_tab. ENDLOOP. IF /afl/comp_tab IS NOT INITIAL. /afl/struct_type = cl_abap_structdescr=>create( /afl/comp_tab ). CREATE DATA /afl/parameter_data TYPE HANDLE /afl/struct_type. ASSIGN /afl/parameter_data->* TO </afl/parameter_data>. LOOP AT /afl/comp_tab ASSIGNING </alf/comp>. true_fieldname = </alf/comp>-name && '[]'. ASSIGN (true_fieldname) TO </afl/parameter>. ASSIGN COMPONENT </alf/comp>-name OF STRUCTURE </afl/parameter_data> TO </afl/parameter_data_field>. </afl/parameter_data_field> = </afl/parameter>. ENDLOOP. &1 = /ui2/cl_json=>serialize( data = </afl/parameter_data> ). ENDIF. END-OF-DEFINITION.
查看记录源代码:

REPORT zafl_viewer. DATA: _log TYPE zafl_log. INCLUDE zafl_macros. SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE TEXT-t00. SELECT-OPTIONS: s_fm FOR _log-fname NO INTERVALS NO-EXTENSION. SELECT-OPTIONS: s_guid FOR _log-guid. SELECT-OPTIONS: s_cf1 FOR _log-cust_field1. SELECT-OPTIONS: s_cf2 FOR _log-cust_field2. SELECT-OPTIONS: s_cf3 FOR _log-cust_field3. SELECT-OPTIONS: s_status FOR _log-status NO INTERVALS. SELECTION-SCREEN END OF BLOCK b1. SELECTION-SCREEN BEGIN OF BLOCK b2 WITH FRAME TITLE TEXT-t01. SELECTION-SCREEN BEGIN OF LINE . SELECTION-SCREEN COMMENT 1(20) TEXT-t02 FOR FIELD p_dstart. PARAMETERS: p_dstart TYPE edidc-upddat DEFAULT sy-datum. SELECTION-SCREEN COMMENT 35(20) TEXT-t03 FOR FIELD p_dend. PARAMETERS: p_dend TYPE edidc-upddat. SELECTION-SCREEN END OF LINE. SELECTION-SCREEN BEGIN OF LINE . SELECTION-SCREEN COMMENT 1(20) TEXT-t04 FOR FIELD p_tstart. PARAMETERS: p_tstart TYPE edidc-updtim DEFAULT '000000'. SELECTION-SCREEN COMMENT 35(20) TEXT-t05 FOR FIELD p_tend. PARAMETERS: p_tend TYPE edidc-updtim DEFAULT '235959'. SELECTION-SCREEN END OF LINE. SELECTION-SCREEN END OF BLOCK b2. * Block: Number Of Hits. SELECTION-SCREEN BEGIN OF BLOCK no_of_hits WITH FRAME TITLE TEXT-t06. SELECTION-SCREEN BEGIN OF LINE. SELECTION-SCREEN COMMENT 1(20) FOR FIELD pv_nofhs. PARAMETERS pv_nofhs TYPE i DEFAULT 1000 MODIF ID nh2. SELECTION-SCREEN POSITION 40. PARAMETERS pc_nhnl AS CHECKBOX USER-COMMAND nh1. SELECTION-SCREEN COMMENT 47(30) TEXT-t07 FOR FIELD pc_nhnl. SELECTION-SCREEN END OF LINE. SELECTION-SCREEN END OF BLOCK no_of_hits. TYPES: ty_time_cond TYPE RANGE OF timestamp. TYPES BEGIN OF ty_log. INCLUDE TYPE zafl_log. TYPES date TYPE sy-datum. TYPES time TYPE sy-uzeit. TYPES time_zone TYPE sy-zonlo. TYPES END OF ty_log. DATA: gt_log TYPE STANDARD TABLE OF ty_log. DATA: gr_alv TYPE REF TO cl_salv_table. CLASS lcl_handle_events DEFINITION. PUBLIC SECTION. METHODS: on_user_command FOR EVENT added_function OF cl_salv_events IMPORTING e_salv_function, on_link_click FOR EVENT link_click OF cl_salv_events_table IMPORTING row column. ENDCLASS. CLASS lcl_handle_events IMPLEMENTATION. METHOD on_user_command. PERFORM handle_user_command USING e_salv_function. ENDMETHOD. "on_user_command "on_double_click METHOD on_link_click. DATA: value TYPE string. READ TABLE gt_log INDEX row ASSIGNING FIELD-SYMBOL(<row>). IF sy-subrc = 0. ASSIGN COMPONENT column OF STRUCTURE <row> TO FIELD-SYMBOL(<value>). IF sy-subrc = 0. value = <value>. ENDIF. ENDIF. IF column = 'FNAME'. DATA(fm_name) = CONV rs38l_fnam( value ). SET PARAMETER ID 'LIB' FIELD fm_name. CALL TRANSACTION 'SE37' AND SKIP FIRST SCREEN. ELSE. cl_demo_output=>display_json( <value> ). ENDIF. ENDMETHOD. "on_single_click ENDCLASS. INITIALIZATION. START-OF-SELECTION. DATA(gr_events) = NEW lcl_handle_events( ). PERFORM get_data. PERFORM display. *&---------------------------------------------------------------------* *& Form GET_DATA *&---------------------------------------------------------------------* * text *----------------------------------------------------------------------* * --> p1 text * <-- p2 text *----------------------------------------------------------------------* FORM get_data. DATA: s_ts TYPE ty_time_cond. PERFORM get_time_cond USING p_dstart p_dend p_tstart p_tend s_ts. SELECT * FROM zafl_log WHERE guid IN @s_guid AND fname IN @s_fm AND cust_field1 IN @s_cf1 AND cust_field2 IN @s_cf2 AND cust_field3 IN @s_cf3 AND status IN @s_status AND timestamp IN @s_ts *INTO TABLE @gt_log INTO CORRESPONDING FIELDS OF TABLE @gt_log UP TO @pv_nofhs ROWS. LOOP AT gt_log ASSIGNING FIELD-SYMBOL(<fs_log>) WHERE timestamp IS NOT INITIAL. <fs_log>-time_zone = sy-zonlo. CONVERT TIME STAMP <fs_log>-timestamp TIME ZONE <fs_log>-time_zone INTO DATE <fs_log>-date TIME <fs_log>-time. ENDLOOP. ENDFORM. FORM get_time_cond USING sdate TYPE dats edate TYPE dats stime TYPE uzeit etime TYPE uzeit result TYPE ty_time_cond. IF sdate IS INITIAL AND edate IS INITIAL. RETURN. ENDIF. DATA(start_date) = sdate. DATA(end_date) = edate. IF end_date IS INITIAL. end_date = start_date. ENDIF. IF start_date IS INITIAL. start_date = end_date. ENDIF. DATA(start_timestamp) = start_date && stime. DATA(end_timestamp) = end_date && etime. result = VALUE #( sign = 'I' option = 'BT' ( low = start_timestamp high = end_timestamp ) ). ENDFORM. *&---------------------------------------------------------------------* *& Form DISPLAY *&---------------------------------------------------------------------* * text *----------------------------------------------------------------------* * --> p1 text * <-- p2 text *----------------------------------------------------------------------* FORM display. TRY. cl_salv_table=>factory( IMPORTING r_salv_table = gr_alv CHANGING t_table = gt_log ). CATCH cx_salv_msg INTO DATA(lr_msg). ENDTRY. DATA(lr_cols) = CAST cl_salv_columns( gr_alv->get_columns( ) ). lr_cols->set_optimize( 'X' ). gr_alv->set_screen_status( pfstatus = 'SALV_STANDARD' report = sy-repid set_functions = gr_alv->c_functions_all ). DATA(lr_selections) = gr_alv->get_selections( ). lr_selections->set_selection_mode( 3 ). DATA: lr_functions TYPE REF TO cl_salv_functions. IF zcl_afl_utilities=>get_distinct_count( tab_data = gt_log field_name = 'FNAME' ) = 1. SELECT SINGLE cust_name1, cust_name2, cust_name3 FROM zafl_config INTO @DATA(config). ENDIF. IF config IS INITIAL. config = VALUE #( cust_name1 = 'CUST_FIELD1' cust_name2 = 'CUST_FIELD2' cust_name3 = 'CUST_FIELD3' ). ENDIF. PERFORM set_column USING '' lr_cols 'GUID' 'GUID' . PERFORM set_column USING 'X' lr_cols 'FNAME' 'Function Module' . PERFORM set_column USING '' lr_cols 'CUST_FIELD1' config-cust_name1. PERFORM set_column USING '' lr_cols 'CUST_FIELD2' config-cust_name2. PERFORM set_column USING '' lr_cols 'CUST_FIELD3' config-cust_name3. PERFORM set_column USING '' lr_cols 'STATUS' 'Status Code' . PERFORM set_column USING '' lr_cols 'TIMESTAMP' 'Timestamp' . PERFORM set_column USING '' lr_cols 'DATE' 'Date' . PERFORM set_column USING '' lr_cols 'TIME' 'Time' . PERFORM set_column USING '' lr_cols 'TIME_ZONE' 'Zone' . PERFORM set_column USING '' lr_cols 'TIME_COST' 'Time Cost' . PERFORM set_column USING '' lr_cols 'UNAME' 'User' . PERFORM set_column USING '' lr_cols 'MESSAGE' 'Message' . PERFORM set_column USING 'X' lr_cols 'IMPORT' 'Import Data' . PERFORM set_column USING 'X' lr_cols 'EXPORT' 'Export Data' . PERFORM set_column USING 'X' lr_cols 'CHANGE_IN' 'Changing In' . PERFORM set_column USING 'X' lr_cols 'CHANGE_OUT' 'Changing Out' . PERFORM set_column USING 'X' lr_cols 'TABLE_IN' 'Tables In ' . PERFORM set_column USING 'X' lr_cols 'TABLE_OUT' 'Tables Out' . DATA(lr_events) = gr_alv->get_event( ). SET HANDLER gr_events->on_user_command FOR lr_events. SET HANDLER gr_events->on_link_click FOR lr_events. gr_alv->display( ). ENDFORM. FORM set_column USING i_hotspot TYPE xfeld pr_cols TYPE REF TO cl_salv_columns VALUE(fname) VALUE(text). DATA: lr_column TYPE REF TO cl_salv_column_table. TRY. lr_column ?= pr_cols->get_column( fname ). lr_column->set_long_text( CONV #( text ) ). lr_column->set_medium_text( CONV #( text ) ). lr_column->set_short_text( CONV #( text ) ). IF i_hotspot = abap_true. lr_column->set_cell_type( if_salv_c_cell_type=>hotspot ). ENDIF. CATCH cx_salv_not_found. "#EC NO_HANDLER ENDTRY. ENDFORM. *&---------------------------------------------------------------------* *& Form HANDLE_USER_COMMAND *&---------------------------------------------------------------------* * text *----------------------------------------------------------------------* * -->P_E_SALV_FUNCTION text *----------------------------------------------------------------------* FORM handle_user_command USING i_ucomm TYPE salv_de_function. CASE i_ucomm. WHEN 'PROCESS'. IF zcl_afl_utilities=>is_prd( ). DATA: ans TYPE c. CALL FUNCTION 'POPUP_TO_CONFIRM' EXPORTING titlebar = 'Confirm'(m01) text_question = 'You have called an IDoc test transaction in a client flagged as "Productive".'(m02) text_button_1 = 'OK' icon_button_1 = 'ICON_CHECKED' text_button_2 = 'CANCEL' icon_button_2 = 'ICON_CANCEL' display_cancel_button = ' ' popup_type = 'ICON_MESSAGE_ERROR' IMPORTING answer = ans. IF ans = 2. RETURN. ENDIF. ENDIF. PERFORM process_selected_rows. WHEN 'REFRESH'. PERFORM get_data. gr_alv->refresh( ). WHEN OTHERS. ENDCASE. ENDFORM. *&---------------------------------------------------------------------* *& Form PROCESS_SELECTED_ROWS *&---------------------------------------------------------------------* * text *----------------------------------------------------------------------* * --> p1 text * <-- p2 text *----------------------------------------------------------------------* FORM process_selected_rows. DATA(lr_selections) = gr_alv->get_selections( ). DATA(lt_rows) = lr_selections->get_selected_rows( ). LOOP AT lt_rows ASSIGNING FIELD-SYMBOL(<row>). READ TABLE gt_log INDEX <row> ASSIGNING FIELD-SYMBOL(<log>). IF sy-subrc = 0. DATA(pass) = zcl_afl_utilities=>fm_authority_check( <log>-fname ). IF pass = abap_false. DATA(msg) = |You are not authorized to test function module { <log>-fname }|. MESSAGE msg TYPE 'S' DISPLAY LIKE 'E'. RETURN. ENDIF. ENDIF. ENDLOOP. LOOP AT lt_rows ASSIGNING <row>. READ TABLE gt_log INDEX <row> ASSIGNING <log>. IF sy-subrc = 0. zcl_afl_utilities=>re_process( <log>-guid ). ENDIF. ENDLOOP. msg = |{ lines( lt_rows ) } records processed|. MESSAGE msg TYPE 'S'. ENDFORM.
