2023 May 30 4:14 PM
Hello experts
In transaction SCMON, there is the button Display Data which allows filtering and displaying data from the tables SCMON*.
In transaction SUSG, I can't find a similar feature to query the tables SUSG* (which contain same kind of data but much older data):
Do you know if there's such a standard feature somewhere? (hidden button, ABAP program or whatever)
Or should I develop it? (quite easy)
Thanks!
I'm using ABAP 7.57 SP 0.
2023 May 31 1:36 PM
sandra.rossi
Hi Sandra,
as far as I know there is still no standard program yet to read the SUSG-data (no clue why, really). There is however this snippet in bfeeb8ed7fa64a7d95efc21f74a8c135's e-Bite "Migrating Custom Code to SAP S/4HANA"
Per SAP, “You cannot display the aggregated usage data (neither in SUSG nor in SCMON or /SDF/SCMON). A remote enabled API is provided to read the aggregated usage data which you can use to implement your own display or extractor.”
Paul then also provides some sample code for such a program and I used that as a starting point to create our own version which provides some more details about the programs executed. Paul has kindly made his code publicly available in his Github repository: https://github.com/hardyp/S4HANA-ABAP-Code-Conversion (Thanks, Paul!)
So, you could use that as a starting point.
Please let me know if you'd like to get more information from the SUSG like I did and I can share the details of what I added to Paul's logic (like information about not just the main program but also each process block).
Hope this helps!
Cheers
Bärbel
2023 May 31 1:36 PM
sandra.rossi
Hi Sandra,
as far as I know there is still no standard program yet to read the SUSG-data (no clue why, really). There is however this snippet in bfeeb8ed7fa64a7d95efc21f74a8c135's e-Bite "Migrating Custom Code to SAP S/4HANA"
Per SAP, “You cannot display the aggregated usage data (neither in SUSG nor in SCMON or /SDF/SCMON). A remote enabled API is provided to read the aggregated usage data which you can use to implement your own display or extractor.”
Paul then also provides some sample code for such a program and I used that as a starting point to create our own version which provides some more details about the programs executed. Paul has kindly made his code publicly available in his Github repository: https://github.com/hardyp/S4HANA-ABAP-Code-Conversion (Thanks, Paul!)
So, you could use that as a starting point.
Please let me know if you'd like to get more information from the SUSG like I did and I can share the details of what I added to Paul's logic (like information about not just the main program but also each process block).
Hope this helps!
Cheers
Bärbel
2023 May 31 5:23 PM
Hi Bärbel, nice, thanks a lot!
I'll try to extend Paul program in the next few days, to add more filter criteria in the selection screen, to make it look like SCMON data display, and I'll post it here.
Thanks for proposing your help. In fact I know better the SUSG tables than the SCMON tables, but of course they are somewhat 95% identical, so I guess it should be fine.
Regards
Sandra
2023 Jun 01 7:02 AM
Hi Sandra,
happy to help!
I added a bit to the selection-screen to be able to also get the called routines:
If checked, the output will contain more details:
I also added the logic to open the code in the editor.
I'm looking forward to what you come up with!
Cheers
Bärbel
2023 Jun 04 9:11 PM
For information of other people, here are the screenshots from Paul original program:
2023 Jun 04 9:09 PM
Here's a program. Note that it was compiled with ABAP 7.57 and S/4HANA 2022.
Feel free to improve it and publish your improvements and fixes.
Column heading "Start Date" is wrong, it's "Last used".
*&---------------------------------------------------------------------*
*&
*& Credits: inspired from Paul Hardy's program ZUSED_Z_CODE_REPORT at https://github.com/hardyp/S4HANA-ABAP-Code-Conversion :
*& https://raw.githubusercontent.com/hardyp/S4HANA-ABAP-Code-Conversion/master/src/zused_z_code_report....
*&
*&---------------------------------------------------------------------*
REPORT z_view_susg.
*&---------------------------------------------------------------------*
*& Report ZUSED_Z_CODE_REPORT
*&---------------------------------------------------------------------*
* There is no standard SAP Program to analyze the results of SCMON/SUSG
* You have to write your own as described in Section 2.2.2
* This is the most basic program I could write to display the data.
* You could add all sorts of bells and whistles, such as automatically
* reclassifying unused objects to a shadow "unused" package hierarchy
*&---------------------------------------------------------------------*
*REPORT zused_z_code_report.
*--------------------------------------------------------------------*
* Seelection Screen
*--------------------------------------------------------------------*
DATA: BEGIN OF dummy_select_options_for,
devclass TYPE tadir-devclass,
usage_kind TYPE susg_admin-kind,
usgid TYPE susg_admin-usgid,
interval TYPE scmon_date4interval,
roottype TYPE scmon_vdata_view-roottype,
rootname TYPE scmon_vdata_view-rootname,
objtype TYPE scmon_vdata_view-object,
objname TYPE scmon_vdata_view-obj_name,
progname TYPE scmon_vdata_view-progname,
proctype TYPE scmon_vdata_view-proctype,
procname TYPE scmon_vdata_view-procname,
class TYPE scmon_vdata_view-classname,
END OF dummy_select_options_for.
"===================
" Package + USGID
"===================
SELECTION-SCREEN BEGIN OF BLOCK frame_miscellaneous WITH FRAME TITLE ft99.
SELECT-OPTIONS s_devc FOR dummy_select_options_for-devclass OBLIGATORY DEFAULT 'Z*' SIGN I OPTION CP.
SELECT-OPTIONS s_kind FOR dummy_select_options_for-usage_kind DEFAULT 'L'.
SELECT-OPTIONS s_usgid FOR dummy_select_options_for-usgid.
SELECTION-SCREEN END OF BLOCK frame_miscellaneous.
"===================
" Calling request entry points
"===================
SELECTION-SCREEN BEGIN OF BLOCK frame_request WITH FRAME TITLE ft01.
SELECTION-SCREEN BEGIN OF LINE.
SELECTION-SCREEN COMMENT (28) txt_rtyp FOR FIELD so_rtype.
SELECT-OPTIONS so_rtype FOR dummy_select_options_for-roottype.
SELECTION-SCREEN END OF LINE.
SELECTION-SCREEN BEGIN OF LINE.
SELECTION-SCREEN COMMENT (28) txt_rnam FOR FIELD so_rname.
SELECT-OPTIONS so_rname FOR dummy_select_options_for-rootname.
SELECTION-SCREEN END OF LINE.
SELECTION-SCREEN END OF BLOCK frame_request.
"===================
" Called objects
"===================
SELECTION-SCREEN BEGIN OF BLOCK frame_object WITH FRAME TITLE ft02.
SELECTION-SCREEN BEGIN OF LINE.
SELECTION-SCREEN COMMENT (28) txt_otyp FOR FIELD so_otype.
SELECT-OPTIONS so_otype FOR dummy_select_options_for-objtype.
SELECTION-SCREEN END OF LINE.
SELECTION-SCREEN BEGIN OF LINE.
SELECTION-SCREEN COMMENT (28) txt_onam FOR FIELD so_oname.
SELECT-OPTIONS so_oname FOR dummy_select_options_for-objname.
SELECTION-SCREEN END OF LINE.
SELECTION-SCREEN BEGIN OF LINE.
SELECTION-SCREEN COMMENT (28) txt_prog FOR FIELD so_prog.
SELECT-OPTIONS so_prog FOR dummy_select_options_for-progname.
SELECTION-SCREEN END OF LINE.
SELECTION-SCREEN END OF BLOCK frame_object.
"===================
" Called procedures
"===================
SELECTION-SCREEN BEGIN OF BLOCK frame_procedure WITH FRAME TITLE ft03.
SELECTION-SCREEN BEGIN OF LINE.
SELECTION-SCREEN COMMENT (28) txt_ptyp FOR FIELD so_ptype.
SELECT-OPTIONS so_ptype FOR dummy_select_options_for-proctype.
SELECTION-SCREEN END OF LINE.
SELECTION-SCREEN BEGIN OF LINE.
SELECTION-SCREEN COMMENT (28) txt_pnam FOR FIELD so_pname.
SELECT-OPTIONS so_pname FOR dummy_select_options_for-procname.
SELECTION-SCREEN END OF LINE.
SELECTION-SCREEN BEGIN OF LINE.
SELECTION-SCREEN COMMENT (28) txt_clas FOR FIELD so_class.
SELECT-OPTIONS so_class FOR dummy_select_options_for-class.
SELECTION-SCREEN END OF LINE.
SELECTION-SCREEN END OF BLOCK frame_procedure.
LOAD-OF-PROGRAM.
CLASS lcl_controller DEFINITION DEFERRED.
DATA controller TYPE REF TO lcl_controller.
CREATE OBJECT controller TYPE ('LCL_CONTROLLER').
*--------------------------------------------------------------------*
* Initialization
*--------------------------------------------------------------------*
INITIALIZATION.
CALL METHOD controller->('INITIALIZATION').
*--------------------------------------------------------------------*
* Start-of-Selection
*--------------------------------------------------------------------*
START-OF-SELECTION.
CALL METHOD controller->('MAIN').
*--------------------------------------------------------------------*
* Class Defintions
*--------------------------------------------------------------------*
CLASS lcl_persistency_layer DEFINITION ##class_final.
PUBLIC SECTION.
TYPES: BEGIN OF g_typ_alv_output,
" Calling object
roottype TYPE scmon_roottype, "scmon_vdata_view-roottype, "susg_sub-roottype,
rootname TYPE susg_sub-rootname,
" Called object
progname TYPE susg_prog-progname,
obj_type TYPE susg_prog-obj_type,
obj_name TYPE susg_prog-obj_name,
devclass TYPE tadir-devclass,
ddtext TYPE char80,
" Called procedure
sub_type TYPE susg_proc-sub_type,
sub_name TYPE susg_proc-sub_name,
counter TYPE susg_data-counter,
last_used TYPE susg_data-last_used,
last_used2 TYPE /sapapo/opt_exp_start_date, " Timestamp TYPE P with conversion routine into Date
END OF g_typ_alv_output.
TYPES: g_tt_alv_output TYPE STANDARD TABLE OF g_typ_alv_output WITH EMPTY KEY.
METHODS derive_all_objects RETURNING VALUE(result) TYPE g_tt_alv_output.
METHODS text_name IMPORTING id_obj_type TYPE tadir-object
id_obj_name TYPE tadir-obj_name
RETURNING VALUE(rd_description) TYPE char80.
METHODS is_an_include IMPORTING id_obj_name TYPE tadir-obj_name
RETURNING VALUE(rf_yes_it_is) TYPE abap_bool.
ENDCLASS.
CLASS lcl_model DEFINITION ##class_final.
PUBLIC SECTION.
DATA: mt_output TYPE lcl_persistency_layer=>g_tt_alv_output,
mo_persistency_layer TYPE REF TO lcl_persistency_layer.
METHODS constructor.
METHODS derive_data.
ENDCLASS.
CLASS lcl_view DEFINITION ##class_final.
PUBLIC SECTION.
METHODS display IMPORTING it_output TYPE lcl_persistency_layer=>g_tt_alv_output.
ENDCLASS.
CLASS lcl_controller DEFINITION ##class_final.
PUBLIC SECTION.
METHODS initialization.
METHODS main.
PRIVATE SECTION.
"! Sets frame titles
METHODS set_frame_titles.
METHODS set_field_texts.
ENDCLASS.
*--------------------------------------------------------------------*
* Class Implementations
*--------------------------------------------------------------------*
CLASS lcl_persistency_layer IMPLEMENTATION.
METHOD derive_all_objects.
SELECT FROM susg_admin
INNER JOIN susg_data
ON susg_data~usgid = susg_admin~usgid
INNER JOIN susg_proc
ON susg_proc~usgid = susg_data~usgid
AND susg_proc~trigid = susg_data~trigid
INNER JOIN susg_prog
ON susg_prog~usgid = susg_proc~usgid
AND susg_prog~progid = susg_proc~progid
INNER JOIN susg_sub
ON susg_sub~usgid = susg_data~usgid
AND susg_sub~subid = susg_data~subid
INNER JOIN tadir
ON tadir~pgmid = 'R3TR'
AND tadir~object = susg_prog~obj_type
AND tadir~obj_name = susg_prog~obj_name
LEFT OUTER JOIN trdirt
ON trdirt~name = susg_prog~obj_name
AND trdirt~sprsl = @sy-langu
AND susg_prog~obj_type EQ 'PROG'
LEFT OUTER JOIN tlibt
ON tlibt~spras EQ @sy-langu
AND tlibt~area EQ susg_prog~obj_name
AND susg_prog~obj_type IN ('FUGR','FUGS')
LEFT OUTER JOIN seoclasstx
ON seoclasstx~langu EQ @sy-langu
AND seoclasstx~clsname EQ susg_prog~obj_name
AND susg_prog~obj_type EQ 'CLAS'
FIELDS DISTINCT susg_sub~roottype, susg_sub~rootname,
susg_prog~progname, susg_prog~obj_type, susg_prog~obj_name,
concat( concat( coalesce( trdirt~text , ' ' ) , coalesce( tlibt~areat , ' ' ) ) , coalesce( seoclasstx~descript , ' ' ) ) AS ddtext,
susg_proc~sub_type, susg_proc~sub_name,
tadir~devclass,
susg_data~counter, susg_data~last_used AS last_used
WHERE tadir~devclass IN @s_devc
AND susg_admin~usgid IN @s_usgid
AND susg_admin~kind IN @s_kind
AND susg_prog~progname IN @s_devc
AND susg_prog~obj_type IN @so_otype
AND susg_prog~obj_name IN @so_oname
" Called procedures
AND susg_proc~sub_type IN @so_ptype
AND susg_proc~sub_name IN @so_pname
AND susg_prog~obj_name IN @so_class
AND susg_sub~roottype IN @so_rtype
AND susg_sub~rootname IN @so_rname
INTO CORRESPONDING FIELDS OF TABLE @result.
IF sy-subrc NE 0.
CLEAR result.
ENDIF.
LOOP AT result REFERENCE INTO DATA(line).
CONVERT DATE line->last_used TIME '000000' INTO TIME STAMP line->last_used2 TIME ZONE ' '.
ENDLOOP.
ENDMETHOD.
METHOD text_name.
ENDMETHOD.
METHOD is_an_include.
SELECT SINGLE subc FROM trdir
INTO @DATA(program_type)
WHERE name = @id_obj_name.
IF sy-subrc EQ 0 AND program_type = 'I'.
rf_yes_it_is = abap_true.
ENDIF.
ENDMETHOD.
ENDCLASS. "lcl_persistency_layer
CLASS lcl_model IMPLEMENTATION.
METHOD constructor.
CREATE OBJECT mo_persistency_layer.
ENDMETHOD.
METHOD derive_data.
mt_output[] = mo_persistency_layer->derive_all_objects( ).
ENDMETHOD.
ENDCLASS.
CLASS lcl_view IMPLEMENTATION.
METHOD display.
DATA(output_table) = it_output."Need copy due to CHANGING parameter
TRY.
cl_salv_table=>factory(
IMPORTING
r_salv_table = DATA(lo_alv_grid)
CHANGING
t_table = output_table ).
CATCH cx_salv_msg INTO DATA(salv_error).
DATA(error_message) = salv_error->get_text( ).
MESSAGE error_message TYPE 'E'.
ENDTRY.
DATA(lo_columns) = lo_alv_grid->get_columns( ).
lo_columns->set_optimize( if_salv_c_bool_sap=>true ).
lo_alv_grid->get_functions( )->set_all( ).
TRY.
DATA(lo_column) = lo_columns->get_column( 'DDTEXT' ).
lo_column->set_long_text( 'Object Description'(005) ).
lo_column->set_short_text( 'Text Name'(004) ).
lo_columns->get_column( 'LAST_USED' )->set_technical( if_salv_c_bool_sap=>true ).
lo_alv_grid->get_sorts( )->add_sort( columnname = 'ROOTTYPE' position = 1 ).
lo_alv_grid->get_sorts( )->add_sort( columnname = 'ROOTNAME' position = 2 ).
lo_alv_grid->get_sorts( )->add_sort( columnname = 'PROGNAME' position = 3 ).
lo_alv_grid->get_sorts( )->add_sort( columnname = 'OBJ_TYPE' position = 4 ).
lo_alv_grid->get_sorts( )->add_sort( columnname = 'OBJ_NAME' position = 5 ).
lo_alv_grid->get_sorts( )->add_sort( columnname = 'DEVCLASS' position = 6 subtotal = 'X' ).
lo_alv_grid->get_sorts( )->add_sort( columnname = 'DDTEXT ' position = 7 ).
lo_alv_grid->get_sorts( )->add_sort( columnname = 'SUB_TYPE' position = 8 ).
lo_alv_grid->get_sorts( )->add_sort( columnname = 'SUB_NAME' position = 9 ).
lo_alv_grid->get_aggregations( )->add_aggregation(
columnname = 'COUNTER'
aggregation = if_salv_c_aggregation=>total ).
lo_alv_grid->get_aggregations( )->add_aggregation(
columnname = 'LAST_USED2'
aggregation = if_salv_c_aggregation=>maximum ).
CATCH cx_salv_error INTO DATA(error).
MESSAGE error TYPE 'E'.
ENDTRY.
lo_alv_grid->display( ).
ENDMETHOD.
ENDCLASS.
CLASS lcl_controller IMPLEMENTATION.
METHOD initialization.
set_field_texts( ).
set_frame_titles( ).
ENDMETHOD.
METHOD main.
DATA(lo_model) = NEW lcl_model( ).
DATA(lo_view) = NEW lcl_view( ).
lo_model->derive_data( ).
lo_view->display( lo_model->mt_output ).
ENDMETHOD.
METHOD set_frame_titles.
ft99 = 'Selection Options'(f99).
ft01 = 'Calling Request Entry Points'(f01).
ft02 = 'Called Objects'(f02).
ft03 = 'Called Procedures'(f03).
ENDMETHOD.
METHOD set_field_texts.
txt_rtyp = 'Type'(rty).
txt_rnam = 'Name'(rna).
txt_otyp = 'Type'(oty).
txt_onam = 'Name'(ona).
txt_prog = 'Program'(pro).
txt_ptyp = 'Type'(typ).
txt_pnam = 'Name'(pna).
txt_clas = 'Called Class Name'(cla).
ENDMETHOD.
ENDCLASS.
2023 Jul 09 4:35 PM
An alternative is to use Solution Manager, SCMON (and/or UPL) data can be aggregated into SolMan infocubes, and there's one BW query to view the data.
Here is how the BW query looks like:
This guide is obtained from SAP Solution Manager WIKI - Custom Code Management - Solution Manager - Support Wiki, there's a "Watch me" link in the section "CCLM 7.2 SP12+: Custom Code Management in Solution Manager 7.2 SP12 and higher":