Ein Audit Trail dokumentiert alle relevanten Aenderungen an Geschaeftsdaten - wer hat wann was geaendert. In ABAP Cloud gibt es verschiedene Ansaetze, von Custom Audit Logs bis zur Integration mit dem SAP Audit Log Service.
Audit Trail vs. Change Documents
Bevor wir in die Implementierung einsteigen, ist es wichtig, den Unterschied zwischen Audit Trail und Change Documents zu verstehen:
| Aspekt | Change Documents | Audit Trail |
|---|---|---|
| Fokus | Technische Feldaenderungen | Geschaeftsrelevante Aktionen |
| Granularitaet | Feldebene (vorher/nachher) | Aktionsebene (was wurde getan) |
| Inhalt | Automatisch alle Felder | Selektiv relevante Informationen |
| Zweck | Nachvollziehbarkeit | Compliance, Forensik |
| Loeschung | Archivierbar | Oft unveraenderbar |
| Rechtskonformitaet | Optional | Oft verpflichtend |
Wann Audit Trail statt Change Documents?
- Regulatorische Anforderungen (SOX, GDPR, GxP)
- Externe Audit-Anforderungen
- Security-relevante Ereignisse (Logins, Berechtigungsaenderungen)
- Geschaeftskritische Transaktionen (Zahlungen, Vertraege)
Audit Trail Anforderungen
Ein professioneller Audit Trail muss folgende Anforderungen erfuellen:
Funktionale Anforderungen
- Vollstaendigkeit: Alle relevanten Ereignisse erfassen
- Unveraenderbarkeit: Keine nachtraegliche Manipulation
- Zeitstempel: Praezise Erfassung des Zeitpunkts
- Benutzeridentifikation: Wer hat die Aktion ausgefuehrt
- Kontextinformationen: Was wurde geaendert (Objekt, Werte)
Technische Anforderungen
- Performance: Minimaler Overhead bei Transaktionen
- Speichereffizienz: Kompakte Datenstruktur
- Abfragbarkeit: Schnelle Suche und Filterung
- Archivierbarkeit: Langzeitspeicherung moeglich
Custom Audit Log Tabelle
Fuer maximale Kontrolle implementieren wir einen eigenen Audit Trail.
Tabellenstruktur
@EndUserText.label: 'Audit Trail Log'@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);}Datentypen fuer Actions
INTERFACE zif_audit_constants PUBLIC.
CONSTANTS: " Action Types 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: " Object Types 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.Audit Logger Klasse
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. " Initialisierung ENDMETHOD.
METHOD log_action. DATA: ls_audit TYPE zaudit_log.
" UUID generieren 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.
" Zeitstempel GET TIME STAMP FIELD ls_audit-created_at.
" Benutzer ls_audit-created_by = cl_abap_context_info=>get_user_technical_name( ).
" Audit Daten 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.
" Session Kontext 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 ).
" In Datenbank schreiben INSERT zaudit_log FROM @ls_audit.
" Bei Fehler: Alternative Protokollierung IF sy-subrc <> 0. " Fallback zu Application Log " Siehe application-logging.md ENDIF. ENDMETHOD.
METHOD get_session_context. " IP-Adresse aus HTTP Request 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.
" Session ID ev_session_id = cl_abap_context_info=>get_session_id( ). ENDMETHOD.
ENDCLASS.RAP Determination fuer Logging
In RAP nutzen wir Determinations, um automatisch Audit Logs zu erstellen. Siehe auch RAP Determinations und Validations.
Behavior Definition
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 fuer Audit Trail determination auditCreate on save { create; } determination auditUpdate on save { update; } determination auditDelete on save { delete; }
" Alle Felder field ( readonly ) OrderId; field ( readonly ) CreatedAt, CreatedBy, LastChangedAt, LastChangedBy;}Determination Implementation
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. " Lese die erstellten Daten 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). " Audit Log erstellen 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 = |Customer: { ls_order-CustomerId }, | && |Amount: { ls_order-NetAmount } { ls_order-Currency }| ). ENDLOOP. ENDMETHOD.
METHOD auditUpdate. " Lese die aktualisierten Daten READ ENTITIES OF zi_salesorder IN LOCAL MODE ENTITY SalesOrder ALL FIELDS WITH CORRESPONDING #( keys ) RESULT DATA(lt_orders).
" Optional: Vorherige Werte fuer Vergleich " Dies erfordert zusaetzliche Logik oder Change Documents
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 = |Status: { ls_order-Status }| ). ENDLOOP. ENDMETHOD.
METHOD auditDelete. " Bei Delete haben wir nur noch die Keys 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 bei RAP Actions
Fuer besonders wichtige Aktionen wie Freigaben:
" In der Behavior Definitionaction approve result [1] $self;action reject result [1] $self;
" In der 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).
" Audit Log fuer Freigabe 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.
" Rueckgabe 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.Audit Log Auswertung
CDS View fuer Audit Log Analyse
@AccessControl.authorizationCheck: #CHECK@EndUserText.label: 'Audit Log Analysis'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,
" Berechnete Felder cast( created_at as abap.dats ) as CreatedDate, substring( cast( created_at as abap.char( 26 ) ), 12, 8 ) as CreatedTime,
" Aggregationen @Aggregation.default: #COUNT 1 as ActionCount}Fiori App fuer Audit Log
@AccessControl.authorizationCheck: #CHECK@EndUserText.label: 'Audit Log'@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: 'Kontext', 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}Abfrage-Service fuer Auswertungen
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. " Beispiel: Viele fehlgeschlagene Logins 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.
" Weitere Kriterien: " - Ungewoehnliche Uhrzeiten " - Viele Loeschungen " - Zugriffe auf sensitive Objekte 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 mit SAP Audit Log Service
Der SAP Audit Log Service auf BTP bietet eine zentrale, manipulationssichere Audit-Loesung.
Service Binding einrichten
Im BTP Cockpit:
- Services > Service Marketplace oeffnen
- Audit Log Service suchen
- Create Instance mit Plan “standard”
- Service Key erstellen fuer ABAP-Zugriff
Communication Arrangement
Communication Scenario: SAP_COM_0193 (Audit Log Integration)
1. Fiori Launchpad > Communication Arrangements2. "New" waehlen3. Scenario: SAP_COM_01934. Communication System mit BTP-Destination verknuepfen5. Inbound Service aktivierenAudit Log Service aufrufen
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. " HTTP Client erstellen 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 ).
" Request bauen DATA(lo_request) = lo_client->get_http_request( ).
" Audit Message als 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' ).
" Request senden 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.Hybrid-Ansatz: Lokal + Cloud
Fuer beste Ergebnisse kombinieren wir lokale und Cloud-Logs:
METHOD log_action_hybrid. " 1. Lokales Audit Log (schnell, immer verfuegbar) 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. Cloud Audit Log (asynchron, manipulationssicher) 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). " Bei Cloud-Fehler: Lokales Log reicht " Optional: Application Log fuer Monitoring ENDTRY.ENDMETHOD.Aufbewahrungsfristen und Archivierung
Gesetzliche Anforderungen
| Regulierung | Aufbewahrungsfrist | Anwendungsbereich |
|---|---|---|
| HGB (DE) | 10 Jahre | Geschaeftsrelevante Dokumente |
| GoBD (DE) | 10 Jahre | Buchhaltungsrelevante Daten |
| SOX (US) | 7 Jahre | Boersennotierte Unternehmen |
| GDPR/DSGVO | Minimierung | Personenbezogene Daten |
| GxP | 15+ Jahre | Pharma/Medizin |
Archivierungs-Job
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. " Berechne Stichtag DATA(lv_cutoff_date) = CONV timestampl( |{ cl_abap_context_info=>get_system_date( ) - iv_retention_days }000000| ).
" 1. Exportiere alte Eintraege (z.B. als JSON) SELECT * FROM zaudit_log WHERE created_at < @lv_cutoff_date INTO TABLE @DATA(lt_archive).
IF lt_archive IS NOT INITIAL. " JSON-Export erstellen DATA(lo_json) = /ui2/cl_json=>serialize( lt_archive ).
" In Archiv-Storage speichern " (z.B. Object Store, Document Management Service) " Siehe: sap-document-management-service.md
" 2. Loesche archivierte Eintraege DELETE FROM zaudit_log WHERE created_at < @lv_cutoff_date.
" 3. Protokolliere Archivierung 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 ) } Eintraege archiviert| ). ENDIF. ENDMETHOD.
ENDCLASS.Background Job einrichten
" Job fuer regelmaessige ArchivierungCLASS 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. " Job-Parameter definieren 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. " Parameter lesen DATA(lv_days) = CONV i( it_parameters[ selname = 'P_DAYS' ]-low ).
" Archivierung ausfuehren NEW zcl_audit_archiver( )->archive_old_entries( lv_days ). ENDMETHOD.
ENDCLASS.Best Practices
1. Performance-Optimierung
" Schlecht: Einzelne INSERTsLOOP AT lt_changes INTO DATA(ls_change). zcl_audit_logger=>log_action( ... ). " Jeder Aufruf = 1 DB-InsertENDLOOP.
" Besser: Bulk-InsertCLASS 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. Asynchrones Logging
Fuer zeitkritische Transaktionen:
" BGPF fuer asynchrones Audit LoggingCLASS 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.
" VerwendungDATA(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. Selektives Logging
Nicht alles loggen - nur relevante Ereignisse:
METHOD should_log_action. " Konfigurierbare Whitelist 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. Sensitive Daten maskieren
METHOD mask_sensitive_data. " Kreditkartennummer maskieren rv_masked = replace( val = iv_data regex = '\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?(\d{4})' with = '****-****-****-$1' ).
" Passwort entfernen rv_masked = replace( val = rv_masked regex = '"password"\s*:\s*"[^"]*"' with = '"password":"***"' ).ENDMETHOD.Zusammenfassung
Ein professioneller Audit Trail in ABAP Cloud erfordert:
| Komponente | Implementierung |
|---|---|
| Speicherung | Custom Tabelle + optional SAP Audit Log Service |
| Erfassung | RAP Determinations fuer automatisches Logging |
| Kontext | User, Timestamp, IP, Session |
| Auswertung | CDS Views + Fiori App |
| Archivierung | Background Job mit Retention Policy |
| Performance | Bulk-Insert, asynchrones Logging |
Weiterführende Themen
- Change Documents - Automatische Feldaenderungs-Protokollierung
- RAP Determinations und Validations - Event-basierte Logik
- Application Logging - Technisches Logging in ABAP