Un Audit Trail documente toutes les modifications pertinentes apportees aux donnees metier - qui a modifie quoi et quand. Dans ABAP Cloud, il existe differentes approches, des Audit Logs personnalises a l’integration avec le SAP Audit Log Service.
Audit Trail vs. Documents de modification
Avant de plonger dans l’implementation, il est important de comprendre la difference entre Audit Trail et Documents de modification :
| Aspect | Documents de modification | Audit Trail |
|---|---|---|
| Focus | Modifications techniques des champs | Actions pertinentes pour le metier |
| Granularite | Niveau champ (avant/apres) | Niveau action (ce qui a ete fait) |
| Contenu | Automatique tous les champs | Informations pertinentes selectionnees |
| Objectif | Tracabilite | Conformite, forensique |
| Suppression | Archivable | Souvent immuable |
| Conformite legale | Optionnel | Souvent obligatoire |
Quand utiliser Audit Trail plutot que Documents de modification ?
- Exigences reglementaires (SOX, RGPD, GxP)
- Exigences d’audit externe
- Evenements lies a la securite (connexions, modifications d’autorisations)
- Transactions critiques pour l’entreprise (paiements, contrats)
Exigences de l’Audit Trail
Un Audit Trail professionnel doit repondre aux exigences suivantes :
Exigences fonctionnelles
- Exhaustivite : Capturer tous les evenements pertinents
- Immuabilite : Pas de manipulation ulterieure
- Horodatage : Capture precise du moment
- Identification de l’utilisateur : Qui a execute l’action
- Informations contextuelles : Ce qui a ete modifie (objet, valeurs)
Exigences techniques
- Performance : Overhead minimal sur les transactions
- Efficacite de stockage : Structure de donnees compacte
- Interrogeabilite : Recherche et filtrage rapides
- Archivabilite : Stockage a long terme possible
Table de log d’audit personnalisee
Pour un controle maximal, nous implementons notre propre Audit Trail.
Structure de table
@EndUserText.label: 'Log Audit Trail"@AbapCatalog.enhancement.category: #NOT_EXTENSIBLE@AbapCatalog.tableCategory: #TRANSPARENT@AbapCatalog.deliveryClass: #L@AbapCatalog.dataMaintenance: #RESTRICTEDdefine table zaudit_log { key client : abap.clnt not null; key log_uuid : sysuuid_x16 not null; created_at : timestampl; created_by : syuname; object_type : abap.char(30); object_key : abap.char(100); action_type : abap.char(20); action_details : abap.string(0); ip_address : abap.char(45); user_agent : abap.char(255); session_id : abap.char(40);}Types de donnees pour les actions
INTERFACE zif_audit_constants PUBLIC.
CONSTANTS: " Types d'action BEGIN OF gc_action, create TYPE string VALUE 'CREATE', update TYPE string VALUE 'UPDATE', delete TYPE string VALUE 'DELETE', read TYPE string VALUE 'READ', approve TYPE string VALUE 'APPROVE', reject TYPE string VALUE 'REJECT', export TYPE string VALUE 'EXPORT', login TYPE string VALUE 'LOGIN', logout TYPE string VALUE 'LOGOUT', auth_fail TYPE string VALUE 'AUTH_FAIL', END OF gc_action.
CONSTANTS: " Types d'objet BEGIN OF gc_object, sales_order TYPE string VALUE 'SALES_ORDER', purchase_order TYPE string VALUE 'PURCHASE_ORDER', customer TYPE string VALUE 'CUSTOMER', vendor TYPE string VALUE 'VENDOR', user TYPE string VALUE 'USER', role TYPE string VALUE 'ROLE', END OF gc_object.
ENDINTERFACE.Classe Audit Logger
CLASS zcl_audit_logger DEFINITION PUBLIC FINAL CREATE PRIVATE.
PUBLIC SECTION. CLASS-METHODS: get_instance RETURNING VALUE(ro_instance) TYPE REF TO zcl_audit_logger,
log_action IMPORTING iv_object_type TYPE string iv_object_key TYPE string iv_action_type TYPE string iv_details TYPE string OPTIONAL.
PRIVATE SECTION. CLASS-DATA: go_instance TYPE REF TO zcl_audit_logger.
METHODS: constructor,
get_session_context EXPORTING ev_ip_address TYPE string ev_user_agent TYPE string ev_session_id TYPE string.
ENDCLASS.
CLASS zcl_audit_logger IMPLEMENTATION.
METHOD get_instance. IF go_instance IS NOT BOUND. go_instance = NEW #( ). ENDIF. ro_instance = go_instance. ENDMETHOD.
METHOD constructor. " Initialisation ENDMETHOD.
METHOD log_action. DATA: ls_audit TYPE zaudit_log.
" Generer UUID TRY. ls_audit-log_uuid = cl_system_uuid=>create_uuid_x16_static( ). CATCH cx_uuid_error. " Fallback GET TIME STAMP FIELD DATA(lv_ts). ls_audit-log_uuid = |{ lv_ts }{ sy-uname }|. ENDTRY.
" Horodatage GET TIME STAMP FIELD ls_audit-created_at.
" Utilisateur ls_audit-created_by = cl_abap_context_info=>get_user_technical_name( ).
" Donnees d'audit ls_audit-object_type = iv_object_type. ls_audit-object_key = iv_object_key. ls_audit-action_type = iv_action_type. ls_audit-action_details = iv_details.
" Contexte de session get_instance( )->get_session_context( IMPORTING ev_ip_address = ls_audit-ip_address ev_user_agent = ls_audit-user_agent ev_session_id = ls_audit-session_id ).
" Ecrire en base de donnees INSERT zaudit_log FROM @ls_audit.
" En cas d'erreur : journalisation alternative IF sy-subrc <> 0. " Fallback vers Application Log " Voir application-logging.md ENDIF. ENDMETHOD.
METHOD get_session_context. " Adresse IP depuis la requete HTTP TRY. DATA(lo_request) = cl_http_server=>if_http_server~get_request( ). ev_ip_address = lo_request->get_header_field( 'x-forwarded-for' ). IF ev_ip_address IS INITIAL. ev_ip_address = lo_request->get_header_field( 'remote_addr' ). ENDIF. ev_user_agent = lo_request->get_header_field( 'user-agent' ). CATCH cx_root. ev_ip_address = 'N/A'. ev_user_agent = 'N/A'. ENDTRY.
" ID de session ev_session_id = cl_abap_context_info=>get_session_id( ). ENDMETHOD.
ENDCLASS.Determination RAP pour la journalisation
Dans RAP, nous utilisons des determinations pour creer automatiquement des logs d’audit. Voir aussi Determinations et validations RAP.
Definition de comportement
managed implementation in class zbp_i_salesorder unique;strict ( 2 );
define behavior for ZI_SalesOrder alias SalesOrderpersistent table zsalesorderlock masterauthorization master ( instance ){ create; update; delete;
" Determination pour Audit Trail determination auditCreate on save { create; } determination auditUpdate on save { update; } determination auditDelete on save { delete; }
" Tous les champs field ( readonly ) OrderId; field ( readonly ) CreatedAt, CreatedBy, LastChangedAt, LastChangedBy;}Implementation des determinations
CLASS lhc_salesorder DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION. METHODS: auditCreate FOR DETERMINE ON SAVE IMPORTING keys FOR SalesOrder~auditCreate,
auditUpdate FOR DETERMINE ON SAVE IMPORTING keys FOR SalesOrder~auditUpdate,
auditDelete FOR DETERMINE ON SAVE IMPORTING keys FOR SalesOrder~auditDelete.
ENDCLASS.
CLASS lhc_salesorder IMPLEMENTATION.
METHOD auditCreate. " Lire les donnees creees READ ENTITIES OF zi_salesorder IN LOCAL MODE ENTITY SalesOrder ALL FIELDS WITH CORRESPONDING #( keys ) RESULT DATA(lt_orders).
LOOP AT lt_orders INTO DATA(ls_order). " Creer le log d'audit zcl_audit_logger=>log_action( iv_object_type = zif_audit_constants=>gc_object-sales_order iv_object_key = |{ ls_order-OrderId }| iv_action_type = zif_audit_constants=>gc_action-create iv_details = |Client: { ls_order-CustomerId }, | && |Montant: { ls_order-NetAmount } { ls_order-Currency }| ). ENDLOOP. ENDMETHOD.
METHOD auditUpdate. " Lire les donnees mises a jour READ ENTITIES OF zi_salesorder IN LOCAL MODE ENTITY SalesOrder ALL FIELDS WITH CORRESPONDING #( keys ) RESULT DATA(lt_orders).
" Optionnel : Valeurs precedentes pour comparaison " Cela necessite une logique supplementaire ou des Documents de modification
LOOP AT lt_orders INTO DATA(ls_order). zcl_audit_logger=>log_action( iv_object_type = zif_audit_constants=>gc_object-sales_order iv_object_key = |{ ls_order-OrderId }| iv_action_type = zif_audit_constants=>gc_action-update iv_details = |Statut: { ls_order-Status }| ). ENDLOOP. ENDMETHOD.
METHOD auditDelete. " Pour Delete, nous n'avons plus que les cles LOOP AT keys INTO DATA(ls_key). zcl_audit_logger=>log_action( iv_object_type = zif_audit_constants=>gc_object-sales_order iv_object_key = |{ ls_key-OrderId }| iv_action_type = zif_audit_constants=>gc_action-delete iv_details = '" ). ENDLOOP. ENDMETHOD.
ENDCLASS.Audit pour les actions RAP
Pour les actions particulierement importantes comme les approbations :
" Dans la definition de comportementaction approve result [1] $self;action reject result [1] $self;
" Dans l'implementationMETHOD approve. MODIFY ENTITIES OF zi_salesorder IN LOCAL MODE ENTITY SalesOrder UPDATE FIELDS ( Status ApprovedAt ApprovedBy ) WITH VALUE #( FOR key IN keys ( %tky = key-%tky Status = 'APPROVED" ApprovedAt = cl_abap_context_info=>get_system_time( ) ApprovedBy = cl_abap_context_info=>get_user_technical_name( ) ) ) FAILED DATA(lt_failed) REPORTED DATA(lt_reported).
" Log d'audit pour l'approbation LOOP AT keys INTO DATA(ls_key). zcl_audit_logger=>log_action( iv_object_type = zif_audit_constants=>gc_object-sales_order iv_object_key = |{ ls_key-OrderId }| iv_action_type = zif_audit_constants=>gc_action-approve iv_details = '" ). ENDLOOP.
" Retour READ ENTITIES OF zi_salesorder IN LOCAL MODE ENTITY SalesOrder ALL FIELDS WITH CORRESPONDING #( keys ) RESULT DATA(lt_orders).
result = VALUE #( FOR order IN lt_orders ( %tky = order-%tky %param = order ) ).ENDMETHOD.Analyse du log d’audit
Vue CDS pour l’analyse du log d’audit
@AccessControl.authorizationCheck: #CHECK@EndUserText.label: 'Analyse du Log Audit"define view entity ZI_AuditLogAnalysis as select from zaudit_log{ key log_uuid as LogUuid, created_at as CreatedAt, created_by as CreatedBy, object_type as ObjectType, object_key as ObjectKey, action_type as ActionType, action_details as ActionDetails, ip_address as IpAddress, session_id as SessionId,
" Champs calcules cast( created_at as abap.dats ) as CreatedDate, substring( cast( created_at as abap.char( 26 ) ), 12, 8 ) as CreatedTime,
" Agregations @Aggregation.default: #COUNT 1 as ActionCount}Application Fiori pour le log d’audit
@AccessControl.authorizationCheck: #CHECK@EndUserText.label: 'Log Audit"@Metadata.allowExtensions: true@Search.searchable: truedefine view entity ZC_AuditLog as projection on ZI_AuditLogAnalysis{ @UI.facet: [ { id: 'General', purpose: #STANDARD, type: #IDENTIFICATION_REFERENCE, label: 'Details', position: 10 }, { id: 'Context', purpose: #STANDARD, type: #FIELDGROUP_REFERENCE, label: 'Contexte', position: 20, targetQualifier: 'Context' } ]
@UI: { lineItem: [{ position: 10 }], identification: [{ position: 10 }] } key LogUuid,
@UI: { lineItem: [{ position: 20, importance: #HIGH }], identification: [{ position: 20 }], selectionField: [{ position: 10 }] } @Search.defaultSearchElement: true CreatedAt,
@UI: { lineItem: [{ position: 30 }], identification: [{ position: 30 }], selectionField: [{ position: 20 }] } @Search.defaultSearchElement: true CreatedBy,
@UI: { lineItem: [{ position: 40, importance: #HIGH }], identification: [{ position: 40 }], selectionField: [{ position: 30 }] } @Search.defaultSearchElement: true ObjectType,
@UI: { lineItem: [{ position: 50 }], identification: [{ position: 50 }] } ObjectKey,
@UI: { lineItem: [{ position: 60, importance: #HIGH }], identification: [{ position: 60 }], selectionField: [{ position: 40 }] } @Consumption.valueHelpDefinition: [{ entity: { name: 'ZI_ActionTypeVH', element: 'ActionType' } }] ActionType,
@UI: { identification: [{ position: 70 }] } ActionDetails,
@UI: { fieldGroup: [{ qualifier: 'Context', position: 10 }] } IpAddress,
@UI: { fieldGroup: [{ qualifier: 'Context', position: 20 }] } SessionId,
CreatedDate, CreatedTime, ActionCount}Service de requete pour les analyses
CLASS zcl_audit_query_service DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION. TYPES: BEGIN OF ty_audit_summary, object_type TYPE string, action_type TYPE string, action_count TYPE i, END OF ty_audit_summary, tt_audit_summary TYPE STANDARD TABLE OF ty_audit_summary WITH EMPTY KEY.
METHODS: get_user_activity IMPORTING iv_user TYPE syuname iv_from_date TYPE timestampl OPTIONAL iv_to_date TYPE timestampl OPTIONAL RETURNING VALUE(rt_log) TYPE STANDARD TABLE OF zaudit_log,
get_object_history IMPORTING iv_object_type TYPE string iv_object_key TYPE string RETURNING VALUE(rt_log) TYPE STANDARD TABLE OF zaudit_log,
get_suspicious_activity RETURNING VALUE(rt_log) TYPE STANDARD TABLE OF zaudit_log,
get_action_summary IMPORTING iv_from_date TYPE timestampl OPTIONAL RETURNING VALUE(rt_summary) TYPE tt_audit_summary.
ENDCLASS.
CLASS zcl_audit_query_service IMPLEMENTATION.
METHOD get_user_activity. DATA(lv_from) = COND #( WHEN iv_from_date IS INITIAL THEN CONV timestampl( '00000000000000' ) ELSE iv_from_date ). DATA(lv_to) = COND #( WHEN iv_to_date IS INITIAL THEN CONV timestampl( '99991231235959' ) ELSE iv_to_date ).
SELECT * FROM zaudit_log WHERE created_by = @iv_user AND created_at BETWEEN @lv_from AND @lv_to ORDER BY created_at DESCENDING INTO TABLE @rt_log. ENDMETHOD.
METHOD get_object_history. SELECT * FROM zaudit_log WHERE object_type = @iv_object_type AND object_key = @iv_object_key ORDER BY created_at DESCENDING INTO TABLE @rt_log. ENDMETHOD.
METHOD get_suspicious_activity. " Exemple : Beaucoup de connexions echouees SELECT * FROM zaudit_log WHERE action_type = @zif_audit_constants=>gc_action-auth_fail AND created_at >= @( cl_abap_context_info=>get_system_date( ) - 1 ) ORDER BY created_at DESCENDING INTO TABLE @rt_log.
" Autres criteres : " - Heures inhabituelles " - Beaucoup de suppressions " - Acces a des objets sensibles ENDMETHOD.
METHOD get_action_summary. DATA(lv_from) = COND #( WHEN iv_from_date IS INITIAL THEN CONV timestampl( '00000000000000' ) ELSE iv_from_date ).
SELECT object_type, action_type, COUNT(*) AS action_count FROM zaudit_log WHERE created_at >= @lv_from GROUP BY object_type, action_type ORDER BY action_count DESCENDING INTO TABLE @rt_summary. ENDMETHOD.
ENDCLASS.Integration avec le SAP Audit Log Service
Le SAP Audit Log Service sur BTP offre une solution d’audit centralisee et inviolable.
Configuration du Service Binding
Dans le BTP Cockpit :
- Services > Service Marketplace ouvrir
- Rechercher Audit Log Service
- Create Instance avec le plan “standard”
- Creer un Service Key pour l’acces ABAP
Communication Arrangement
Communication Scenario: SAP_COM_0193 (Audit Log Integration)
1. Fiori Launchpad > Communication Arrangements2. Choisir "New"3. Scenario: SAP_COM_01934. Lier le Communication System avec la destination BTP5. Activer le service entrantAppel du Audit Log Service
CLASS zcl_audit_log_service DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION. METHODS: write_audit_log IMPORTING iv_object_type TYPE string iv_object_id TYPE string iv_action TYPE string iv_attributes TYPE string_table OPTIONAL RAISING cx_static_check.
ENDCLASS.
CLASS zcl_audit_log_service IMPLEMENTATION.
METHOD write_audit_log. " Creer le client HTTP DATA(lo_destination) = cl_http_destination_provider=>create_by_cloud_destination( i_name = 'AUDIT_LOG_SERVICE" ).
DATA(lo_client) = cl_web_http_client_manager=>create_by_http_destination( lo_destination ).
" Construire la requete DATA(lo_request) = lo_client->get_http_request( ).
" Message d'audit en JSON DATA(lv_timestamp) = |{ sy-datum }T{ sy-uzeit }Z|. DATA(lv_user) = cl_abap_context_info=>get_user_technical_name( ).
DATA(lv_json) = |\{| && |"uuid":"{ cl_system_uuid=>create_uuid_c36_static( ) }",| && |"time":"{ lv_timestamp }",| && |"user":"{ lv_user }",| && |"object":\{| && |"type":"{ iv_object_type }",| && |"id":\{"key":"{ iv_object_id }"\}| && |\},| && |"action":"{ iv_action }"| && |\}|.
lo_request->set_text( lv_json ). lo_request->set_header_field( i_name = 'Content-Type" i_value = 'application/json" ).
" Envoyer la requete DATA(lo_response) = lo_client->execute( if_web_http_client=>post ).
IF lo_response->get_status( )-code <> 201. RAISE EXCEPTION TYPE cx_abap_not_a_number MESSAGE e001(zaudit) WITH lo_response->get_status( )-reason. ENDIF.
lo_client->close( ). ENDMETHOD.
ENDCLASS.Approche hybride : Local + Cloud
Pour de meilleurs resultats, nous combinons les logs locaux et cloud :
METHOD log_action_hybrid. " 1. Log d'audit local (rapide, toujours disponible) zcl_audit_logger=>log_action( iv_object_type = iv_object_type iv_object_key = iv_object_key iv_action_type = iv_action_type iv_details = iv_details ).
" 2. Log d'audit cloud (asynchrone, inviolable) TRY. NEW zcl_audit_log_service( )->write_audit_log( iv_object_type = iv_object_type iv_object_id = iv_object_key iv_action = iv_action_type ). CATCH cx_static_check INTO DATA(lx_error). " En cas d'erreur cloud : le log local suffit " Optionnel : Application Log pour la surveillance ENDTRY.ENDMETHOD.Durees de conservation et archivage
Exigences legales
| Reglementation | Duree de conservation | Domaine d’application |
|---|---|---|
| HGB (DE) | 10 ans | Documents commerciaux |
| GoBD (DE) | 10 ans | Donnees comptables |
| SOX (US) | 7 ans | Entreprises cotees en bourse |
| RGPD/DSGVO | Minimisation | Donnees personnelles |
| GxP | 15+ ans | Pharma/Medical |
Job d’archivage
CLASS zcl_audit_archiver DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION. METHODS: archive_old_entries IMPORTING iv_retention_days TYPE i DEFAULT 365.
ENDCLASS.
CLASS zcl_audit_archiver IMPLEMENTATION.
METHOD archive_old_entries. " Calculer la date limite DATA(lv_cutoff_date) = CONV timestampl( |{ cl_abap_context_info=>get_system_date( ) - iv_retention_days }000000| ).
" 1. Exporter les anciennes entrees (par ex. en JSON) SELECT * FROM zaudit_log WHERE created_at < @lv_cutoff_date INTO TABLE @DATA(lt_archive).
IF lt_archive IS NOT INITIAL. " Creer l'export JSON DATA(lo_json) = /ui2/cl_json=>serialize( lt_archive ).
" Sauvegarder dans le stockage d'archive " (par ex. Object Store, Document Management Service) " Voir: sap-document-management-service.md
" 2. Supprimer les entrees archivees DELETE FROM zaudit_log WHERE created_at < @lv_cutoff_date.
" 3. Journaliser l'archivage zcl_audit_logger=>log_action( iv_object_type = 'AUDIT_LOG" iv_object_key = |ARCHIVE_{ sy-datum }| iv_action_type = 'ARCHIVE" iv_details = |{ lines( lt_archive ) } entrees archivees| ). ENDIF. ENDMETHOD.
ENDCLASS.Configurer le job en arriere-plan
" Job pour archivage regulierCLASS zcl_audit_archive_job DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION. INTERFACES: if_apj_dt_exec_object, if_apj_rt_exec_object.
ENDCLASS.
CLASS zcl_audit_archive_job IMPLEMENTATION.
METHOD if_apj_dt_exec_object~get_parameters. " Definir les parametres du job et_parameter_def = VALUE #( ( selname = 'P_DAYS" kind = if_apj_dt_exec_object=>parameter datatype = 'INT4" mandatory = abap_false changeable_ind = abap_true ) ).
et_parameter_val = VALUE #( ( selname = 'P_DAYS' sign = 'I' option = 'EQ' low = '365' ) ). ENDMETHOD.
METHOD if_apj_rt_exec_object~execute. " Lire le parametre DATA(lv_days) = CONV i( it_parameters[ selname = 'P_DAYS' ]-low ).
" Executer l'archivage NEW zcl_audit_archiver( )->archive_old_entries( lv_days ). ENDMETHOD.
ENDCLASS.Bonnes pratiques
1. Optimisation des performances
" Mauvais : INSERT individuelsLOOP AT lt_changes INTO DATA(ls_change). zcl_audit_logger=>log_action( ... ). " Chaque appel = 1 INSERT BDENDLOOP.
" Meilleur : INSERT en masseCLASS zcl_audit_logger DEFINITION. CLASS-METHODS: log_actions_bulk IMPORTING it_audit_entries TYPE tt_audit_entries.ENDCLASS.
METHOD log_actions_bulk. INSERT zaudit_log FROM TABLE @it_audit_entries.ENDMETHOD.2. Journalisation asynchrone
Pour les transactions critiques en temps :
" BGPF pour journalisation d'audit asynchroneCLASS zcl_audit_async DEFINITION. INTERFACES: if_bgmc_op_single.
DATA: ms_audit TYPE zaudit_log.ENDCLASS.
METHOD if_bgmc_op_single~execute. INSERT zaudit_log FROM @ms_audit.ENDMETHOD.
" UtilisationDATA(lo_async) = NEW zcl_audit_async( ).lo_async->ms_audit = ls_audit_entry.
cl_bgmc_process_factory=>get_default( )->create( )->set_operation_single( lo_async )->save_for_execution( ).3. Journalisation selective
Ne pas tout journaliser - seulement les evenements pertinents :
METHOD should_log_action. " Liste blanche configurable SELECT SINGLE @abap_true FROM zaudit_config WHERE object_type = @iv_object_type AND action_type = @iv_action_type AND is_active = @abap_true INTO @rv_should_log.ENDMETHOD.4. Masquer les donnees sensibles
METHOD mask_sensitive_data. " Masquer le numero de carte de credit rv_masked = replace( val = iv_data regex = '\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?(\d{4})" with = '****-****-****-$1" ).
" Supprimer le mot de passe rv_masked = replace( val = rv_masked regex = '"password"\s*:\s*"[^"]*"" with = '"password":"***"" ).ENDMETHOD.Resume
Un Audit Trail professionnel dans ABAP Cloud necessite :
| Composant | Implementation |
|---|---|
| Stockage | Table personnalisee + optionnel SAP Audit Log Service |
| Capture | Determinations RAP pour journalisation automatique |
| Contexte | Utilisateur, horodatage, IP, session |
| Analyse | Vues CDS + application Fiori |
| Archivage | Job en arriere-plan avec politique de retention |
| Performance | INSERT en masse, journalisation asynchrone |
Sujets connexes
- Documents de modification - Journalisation automatique des modifications de champs
- Determinations et validations RAP - Logique basee sur les evenements
- Application Logging - Journalisation technique en ABAP