SCU3 SCD0: Log Data Changes

Folgende Info ist nicht verifiziert:

SE11 Technical Settings / Log Data Changes

Setting Systeme Profile Paraemter Rec/Client (DEFAULT OFF)

Setting Rec/Client Parameter for Logging

SCU3 View Table Logging of all tables which have got Log Data Changes ON

oder

SCDO

Change log for Z-Table Maintenance (via SCDO)

Generally we don’t need table logging for custom table maintenance (SM30), but it is important and needed for some cases. All customizing tables are automatically recorded by default but if you use regular Application tables (master and transaction data), you’re about to get your hands dirty .)

Z-TableSample Z-Table

Automatic table change logging

Actually this is not suitable for our case because we want to log particular tables but it’s good to know..

You can use Automatic table change logging by setting the “Log Data Changes” flag under the table “Technical Settings” in SE11 (p.s. You must activate the table again after saving it, otherwise it will not be effective).

Next, to be able to log the table changes you must activate the system profile parameter Rec/Client. The default setting is OFF (no changes are logged). BASIS Team can assist you in this.
Setting Rec/Client Parameter for Logging

However, SAP recommends this option only in systems where this is worthwhile, because all tables with “Log data changes” option will be logged, so this has a major impact on performance (Even for one client)

You can now view the changes via SCU3 (Table: DBTABLOG)

SCU3-Logs
SCU3-Logs

Logging using Change Document Objects (SCDO)

To log changes for particular tables in SM30 Maintenance, we can use change document objects and its associated functions.

Let’s do it step by step;

  • Go to SCDO and create a Change Document Object (Choose Yes for opening Namespace Pop-ups)
    SCDO-Create
  • Insert the entries and choose Utilities → Generate update pgm.SCDO-Insert Entries
  • In the opening pop-up, give function group name (it will be created if it doesn’t exist) and generate the update program for the object by clicking Activate. SCDO-Generated
  • In the Data Element → Further Characteristics Tab, set the “Change Document” flag for the objects which you want to track changes. As you recognise, many SAP standard data elements come with the selected flag.
  • You can now insert appropriate calls in the corresponding programs, for our example we will use Table Maintenance Events.
  • Under the table maintenance (SE56) go to Environment → Modification → Events.
    Give the events & subroutine names as shown in the figure and click the Editor icon to create suggested include (L<fg_name>F01).
    SM30-Events

Now, you can just copy and paste the code snippet (link is below) into the created include. It will begin to create logs in CDHDR-CDPOS tables. You can now view the changes via reports CHANGEDOCU_READ & RSSCD100.

SCDO-Logs SCDO-Logs

*&----------------------------------------------------------------*
*&      Form  F_BEFORE_SAVE
*&----------------------------------------------------------------*
FORM f_before_save ##CALLED.
  TYPES: BEGIN OF ty_tcdrp,
           object     TYPE cdobjectcl,
           reportname TYPE cdreport,
         END OF   ty_tcdrp,
         BEGIN OF ty_view_tab,
           object  TYPE cdobjectcl,
           tabname TYPE cdtabname,
         END OF   ty_view_tab.
  DATA: lt_ptab      TYPE STANDARD TABLE OF string,
        lv_prog      TYPE string,
        lv_mess      TYPE string,
        lv_sid       TYPE string,
        lt_obj       TYPE STANDARD TABLE OF ty_view_tab,
        lt_tcdrp     TYPE STANDARD TABLE OF ty_tcdrp,
        lv_fugn      TYPE funct_pool,
        lv_table     TYPE cdtabname,
        lv_namesfunc TYPE namespace,
        lv_funcgroup TYPE progname,
        lv_namesprog TYPE namespace,
        lv_program   TYPE progname,
        lrt_tabname  TYPE RANGE OF tabname,
        lt_dd26v     TYPE TABLE OF dd26v,
        lv_object    TYPE cdobjectcl.
  " Get tabnames
  " DD: Interface for reading a view from the ABAP/4 Dictionary
  CALL FUNCTION 'DDIF_VIEW_GET'
    EXPORTING
      name          = vim_view_name
    TABLES
      dd26v_tab     = lt_dd26v
    EXCEPTIONS
      illegal_input = 1
      OTHERS        = 2.
  IF sy-subrc IS NOT INITIAL.
    MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
            WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
  ENDIF.
  IF lt_dd26v IS INITIAL.
    APPEND INITIAL LINE TO lrt_tabname ASSIGNING FIELD-SYMBOL(<lrs_tabname>).
    <lrs_tabname>-sign   = 'I'.
    <lrs_tabname>-option = 'EQ'.
    <lrs_tabname>-low    = vim_view_name.
  ELSE.
    SORT lt_dd26v BY tabname.
    DELETE ADJACENT DUPLICATES FROM lt_dd26v COMPARING tabname.
    "*-
    LOOP AT lt_dd26v INTO DATA(ls_dd26v).
      APPEND INITIAL LINE TO lrt_tabname ASSIGNING <lrs_tabname>.
      <lrs_tabname>-sign   = 'I'.
      <lrs_tabname>-option = 'EQ'.
      <lrs_tabname>-low    = ls_dd26v-tabname.
    ENDLOOP.
  ENDIF.
  " Objects for change document creation
  SELECT object tabname
    FROM tcdob
    INTO TABLE lt_obj
    WHERE tabname IN lrt_tabname
    ##WARN_OK.
  IF sy-subrc IS NOT INITIAL.
    " No change document objects found
    MESSAGE i899(cd).
    RETURN.
  ENDIF.
  " Information on Include Reports Generated by RSSCD000
  SELECT object reportname
    FROM tcdrp
    INTO TABLE lt_tcdrp
    FOR ALL ENTRIES IN lt_obj
    WHERE object EQ lt_obj-object
    ##WARN_OK.
  IF sy-subrc IS NOT INITIAL.
    " Update program does not yet exist
    MESSAGE i446(m2).
    RETURN.
  ENDIF.
  " View Directory
  SELECT SINGLE area
    FROM tvdir
    INTO lv_fugn
    WHERE tabname EQ vim_view_name.
  "*-
  LOOP AT lt_obj ASSIGNING FIELD-SYMBOL(<ls_obj>).
    READ TABLE lt_tcdrp ASSIGNING FIELD-SYMBOL(<ls_tcdrp>)
                        WITH KEY object = <ls_obj>-object.
    IF sy-subrc IS NOT INITIAL.
      CONTINUE.
    ENDIF.
    " Split namespace
    CLEAR: lv_namesprog, lv_program.
    lv_program = <ls_tcdrp>-reportname.
    CALL FUNCTION 'RS_NAME_SPLIT_NAMESPACE'
      EXPORTING
        name_with_namespace    = lv_program
      IMPORTING
        namespace              = lv_namesprog
        name_without_namespace = lv_program
      EXCEPTIONS
        delimiter_error        = 1
        OTHERS                 = 2.
    IF sy-subrc <> 0.
      lv_program = <ls_tcdrp>-reportname.
    ENDIF.
    CLEAR: lv_namesfunc, lv_funcgroup.
    lv_funcgroup = lv_fugn.
    CALL FUNCTION 'RS_NAME_SPLIT_NAMESPACE'
      EXPORTING
        name_with_namespace    = lv_funcgroup
      IMPORTING
        namespace              = lv_namesfunc
        name_without_namespace = lv_funcgroup
      EXCEPTIONS
        delimiter_error        = 1
        OTHERS                 = 2.
    IF sy-subrc <> 0.
      lv_funcgroup = lv_fugn.
    ENDIF.
    " Namespace conversion
    lv_object = <ls_obj>-object.
    IF lv_object(1) = '/'.
      SHIFT lv_object LEFT DELETING LEADING '/'.
      REPLACE FIRST OCCURRENCE OF '/' IN lv_object WITH '_'.
    ENDIF.
    lv_table = <ls_obj>-tabname.
    IF lv_table(1) = '/'.
      SHIFT lv_table LEFT DELETING LEADING '/'.
      REPLACE FIRST OCCURRENCE OF '/' IN lv_table WITH '_'.
    ENDIF.
    " Subroutine pool
    APPEND ##NO_TEXT:
           `PROGRAM SUBPOOL.` TO lt_ptab,
           `  INCLUDE ` && lv_namesprog  && `F` && lv_program && `CDT.` TO lt_ptab,
           `  INCLUDE ` && lv_namesprog  && `F` && lv_program && `CDC.` TO lt_ptab,
           `  FORM f_process.` TO lt_ptab,
           `    TYPES:  BEGIN OF total.` TO lt_ptab,
           `            INCLUDE STRUCTURE ` && vim_view_name && `.` TO lt_ptab,
           `            INCLUDE STRUCTURE vimflagtab.` TO lt_ptab,
           `    TYPES:  END OF total.` TO lt_ptab,
           `    FIELD-SYMBOLS: <fs_total>       TYPE ANY TABLE,` TO lt_ptab,
           `                   <fs_total_wa>    TYPE total,` TO lt_ptab,
           `                   <fs_x_namtab>    TYPE ANY TABLE,` TO lt_ptab,
           `                   <fs_x_namtab_wa> TYPE vimnamtab,` TO lt_ptab,
           `                   <fs_field>       TYPE any.` TO lt_ptab,
           `    DATA: lv_tabname(40) TYPE c VALUE '(` && lv_namesfunc && `SAPL` && lv_funcgroup && `)TOTAL[]',` TO lt_ptab,
           `          lv_cond_line  TYPE string,` TO lt_ptab,
           `          lv_cond_line2 TYPE string.` TO lt_ptab,
           `    ASSIGN (lv_tabname) TO <fs_total>.` TO lt_ptab,
           `    LOOP AT <fs_total> ASSIGNING <fs_total_wa> CASTING.` TO lt_ptab,
           `      CASE <fs_total_wa>-action.` TO lt_ptab,
           `        WHEN 'U'. " Update` TO lt_ptab,
           `          lv_tabname = '(` && lv_namesfunc && `SAPL` && lv_funcgroup && `)X_NAMTAB[]'.` TO lt_ptab,
           `          ASSIGN (lv_tabname) TO <fs_x_namtab>.` TO lt_ptab,
           `          lv_cond_line2 = |keyflag EQ 'X' AND viewfield NE 'MANDT'|.` TO lt_ptab,
           `          LOOP AT <fs_x_namtab> ASSIGNING <fs_x_namtab_wa> WHERE (lv_cond_line2).` TO lt_ptab,
           `            ASSIGN COMPONENT <fs_x_namtab_wa>-viewfield OF STRUCTURE <fs_total_wa> TO <fs_field>.` TO lt_ptab,
           `            IF sy-subrc IS INITIAL.` TO lt_ptab,
           `              lv_cond_line = lv_cond_line && |AND | && ` TO lt_ptab,
           `                             <fs_x_namtab_wa>-viewfield && | EQ '| && <fs_field> && |' |.` TO lt_ptab,
           `              objectid = objectid && <fs_field>.` TO lt_ptab,
           `              UNASSIGN <fs_field>.` TO lt_ptab,
           `            ENDIF.` TO lt_ptab,
           `          ENDLOOP.` TO lt_ptab,
           `          IF sy-subrc IS INITIAL.` TO lt_ptab,
           `            SHIFT lv_cond_line LEFT BY 3 PLACES.` TO lt_ptab,
           `            SELECT SINGLE *` TO lt_ptab,
           `              FROM ` && <ls_obj>-tabname TO lt_ptab,
           `              INTO *` && <ls_obj>-tabname TO lt_ptab,
           `              WHERE (lv_cond_line).` TO lt_ptab,
           `            MOVE-CORRESPONDING <fs_total_wa> TO ` && <ls_obj>-tabname && `.` TO lt_ptab,
           `            objectid        = objectid.` TO lt_ptab,
           `            tcode           = sy-tcode.` TO lt_ptab,
           `            udate           = sy-datum.` TO lt_ptab,
           `            utime           = sy-uzeit.` TO lt_ptab,
           `            username        = sy-uname.` TO lt_ptab,
           `            cdoc_upd_object = 'U'.` TO lt_ptab,
           `            upd_` && lv_table && ` = 'U'.` TO lt_ptab,
           `            PERFORM cd_call_` && lv_object && `.` TO lt_ptab,
           `          ENDIF.` TO lt_ptab,
           `        WHEN 'N'. " New` TO lt_ptab,
           `          lv_tabname = '(` && lv_namesfunc && `SAPL` && lv_funcgroup && `)X_NAMTAB[]'.` TO lt_ptab,
           `          ASSIGN (lv_tabname) TO <fs_x_namtab>.` TO lt_ptab,
           `          lv_cond_line2 = |keyflag EQ 'X' AND viewfield NE 'MANDT'|.` TO lt_ptab,
           `          LOOP AT <fs_x_namtab> ASSIGNING <fs_x_namtab_wa> WHERE (lv_cond_line2).` TO lt_ptab,
           `            ASSIGN COMPONENT <fs_x_namtab_wa>-viewfield OF STRUCTURE <fs_total_wa> TO <fs_field>.` TO lt_ptab,
           `            IF sy-subrc IS INITIAL.` TO lt_ptab,
           `              objectid = objectid && <fs_field>.` TO lt_ptab,
           `              UNASSIGN <fs_field>.` TO lt_ptab,
           `            ENDIF.` TO lt_ptab,
           `          ENDLOOP.` TO lt_ptab,
           `          IF sy-subrc IS INITIAL.` TO lt_ptab,
           `            MOVE-CORRESPONDING <fs_total_wa> TO ` && <ls_obj>-tabname && `.` TO lt_ptab,
           `            objectid        = objectid.` TO lt_ptab,
           `            tcode           = sy-tcode.` TO lt_ptab,
           `            udate           = sy-datum.` TO lt_ptab,
           `            utime           = sy-uzeit.` TO lt_ptab,
           `            username        = sy-uname.` TO lt_ptab,
           `            cdoc_upd_object = 'I'.` TO lt_ptab,
           `            upd_` && lv_table && ` = 'I'.` TO lt_ptab,
           `            PERFORM cd_call_` && lv_object && `.` TO lt_ptab,
           `          ENDIF.` TO lt_ptab,
           `        WHEN 'D'. " Delete` TO lt_ptab,
           `          lv_tabname = '(` && lv_namesfunc && `SAPL` && lv_funcgroup && `)X_NAMTAB[]'.` TO lt_ptab,
           `          ASSIGN (lv_tabname) TO <fs_x_namtab>.` TO lt_ptab,
           `          lv_cond_line2 = |keyflag EQ 'X' AND viewfield NE 'MANDT'|.` TO lt_ptab,
           `          LOOP AT <fs_x_namtab> ASSIGNING <fs_x_namtab_wa> WHERE (lv_cond_line2).` TO lt_ptab,
           `            ASSIGN COMPONENT <fs_x_namtab_wa>-viewfield OF STRUCTURE <fs_total_wa> TO <fs_field>.` TO lt_ptab,
           `            IF sy-subrc IS INITIAL.` TO lt_ptab,
           `              objectid = objectid && <fs_field>.` TO lt_ptab,
           `              UNASSIGN <fs_field>.` TO lt_ptab,
           `            ENDIF.` TO lt_ptab,
           `          ENDLOOP.` TO lt_ptab,
           `          IF sy-subrc IS INITIAL.` TO lt_ptab,
           `            MOVE-CORRESPONDING <fs_total_wa> TO *` && <ls_obj>-tabname && `.` TO lt_ptab,
           `            objectid        = objectid.` TO lt_ptab,
           `            tcode           = sy-tcode.` TO lt_ptab,
           `            udate           = sy-datum.` TO lt_ptab,
           `            utime           = sy-uzeit.` TO lt_ptab,
           `            username        = sy-uname.` TO lt_ptab,
           `            cdoc_upd_object = 'D'.` TO lt_ptab,
           `            upd_` && lv_table && ` = 'D'.` TO lt_ptab,
           `            PERFORM cd_call_` && lv_object && `.` TO lt_ptab,
           `          ENDIF.` TO lt_ptab,
           `      ENDCASE.` TO lt_ptab,
           `      CLEAR: lv_cond_line, lv_cond_line2, objectid, ` && <ls_obj>-tabname && `, *` && <ls_obj>-tabname && `.` TO lt_ptab,
           `    ENDLOOP.` TO lt_ptab,
           `  ENDFORM.` TO lt_ptab.
    "*-
    GENERATE SUBROUTINE POOL lt_ptab NAME lv_prog
             MESSAGE lv_mess
             SHORTDUMP-ID lv_sid.
    IF sy-subrc = 0.
      PERFORM ('F_PROCESS') IN PROGRAM (lv_prog) IF FOUND.
    ELSEIF sy-subrc = 4.
      MESSAGE lv_mess TYPE 'I'.
    ELSEIF sy-subrc = 8.
      MESSAGE lv_sid TYPE 'I'.
    ENDIF.
    CLEAR: lt_ptab.
  ENDLOOP.
ENDFORM.
*&----------------------------------------------------------------*
*&      Form  F_AFTER_SAVE
*&----------------------------------------------------------------*
FORM f_after_save ##CALLED.
  COMMIT WORK AND WAIT.
ENDFORM.