ABAP Environment Monitoring ist essenziell fuer den stabilen Betrieb deiner ABAP Cloud-Anwendungen auf SAP BTP. Anders als On-Premise stehen dir auf BTP spezialisierte Cloud-native Monitoring-Tools zur Verfuegung, die Health, Performance und Jobs ueberwachen.
Verfuegbare Monitoring-Tools
SAP BTP ABAP Environment bietet verschiedene Ebenen der Ueberwachung:
| Tool | Zweck | Zielgruppe |
|---|---|---|
| SAP BTP Cockpit | Infrastruktur-Monitoring | Cloud Administrator |
| Fiori App: Health Monitoring | Systemgesundheit | ABAP Administrator |
| Fiori App: SQL Trace Analysis | Performance-Diagnose | Entwickler/Admin |
| Fiori App: ABAP Runtime Errors | Fehleranalyse | Entwickler |
| Fiori App: Manage Background Tasks | Job-Ueberwachung | Administrator |
| Application Jobs | Job-Scheduling und Status | Administrator |
| Application Logs | Protokoll-Analyse | Entwickler/Admin |
| SAP Cloud ALM | Enterprise Monitoring | IT Operations |
Architektur-Uebersicht
┌─────────────────────────────────────────────────────────────────────────────┐│ SAP BTP ABAP Environment Monitoring ││ ││ ┌────────────────────────────────────────────────────────────────────────┐ ││ │ SAP BTP Cockpit │ ││ │ - Service Health │ ││ │ - Resource Usage (Memory, CPU) │ ││ │ - Connectivity Status │ ││ └────────────────────────────────────────────────────────────────────────┘ ││ │ ││ ▼ ││ ┌────────────────────────────────────────────────────────────────────────┐ ││ │ ABAP Environment Instance │ ││ │ │ ││ │ ┌─────────────────────┐ ┌─────────────────────┐ │ ││ │ │ Health Monitoring │ │ SQL Trace Analysis │ │ ││ │ │ (System Health) │ │ (Performance) │ │ ││ │ └─────────────────────┘ └─────────────────────┘ │ ││ │ │ ││ │ ┌─────────────────────┐ ┌─────────────────────┐ │ ││ │ │ Application Jobs │ │ Application Logs │ │ ││ │ │ (Background Tasks) │ │ (Protokolle) │ │ ││ │ └─────────────────────┘ └─────────────────────┘ │ ││ │ │ ││ │ ┌─────────────────────┐ ┌─────────────────────┐ │ ││ │ │ ABAP Runtime Errors│ │ Communication │ │ ││ │ │ (ST22 Cloud) │ │ Arrangements │ │ ││ │ └─────────────────────┘ └─────────────────────┘ │ ││ └────────────────────────────────────────────────────────────────────────┘ ││ │ ││ ▼ ││ ┌────────────────────────────────────────────────────────────────────────┐ ││ │ SAP Cloud ALM (optional) │ ││ │ - Cross-System Monitoring │ ││ │ - Alerting & Notifications │ ││ │ - Operations Dashboard │ ││ └────────────────────────────────────────────────────────────────────────┘ │└─────────────────────────────────────────────────────────────────────────────┘Health Monitoring und Alerts
Fiori App: Health Monitoring
Die App “Health Monitoring” (App-ID: F5687) zeigt den aktuellen Gesundheitszustand des ABAP Systems:
┌────────────────────────────────────────────────────────────────────────────┐│ Health Monitoring ││ ││ System Status: ● Healthy Last Check: 14.02.2026 10:23 ││ ││ ┌──────────────────────────────────────────────────────────────────────┐ ││ │ Key Metrics │ ││ │ │ ││ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ ││ │ │ Memory │ │ CPU │ │ DB Conns │ │ Sessions │ │ ││ │ │ 72% │ │ 45% │ │ 23/100 │ │ 15/50 │ │ ││ │ │ ████████░░│ │ █████░░░░░│ │ ███░░░░░░░│ │ ██░░░░░░░░│ │ ││ │ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │ ││ └──────────────────────────────────────────────────────────────────────┘ ││ ││ Recent Events: ││ ⚠ 10:15 - High memory usage detected (85%) ││ ✓ 09:45 - Scheduled maintenance completed ││ ✓ 09:00 - Daily health check passed │└────────────────────────────────────────────────────────────────────────────┘Wichtige Health-Metriken
| Metrik | Beschreibung | Kritischer Schwellwert |
|---|---|---|
| Memory Usage | Speicherauslastung des ABAP Systems | > 90% |
| CPU Usage | Prozessorauslastung | > 85% sustained |
| DB Connections | Aktive Datenbankverbindungen | > 80% des Limits |
| Work Processes | Verfuegbare Dialog/Background WPs | < 20% frei |
| Response Time | Durchschnittliche Antwortzeit | > 2 Sekunden |
| Active Sessions | Angemeldete Benutzer | > 80% des Limits |
Alerting mit SAP Cloud ALM
" Programmtisches Alert-Monitoring ueber APICLASS zcl_health_monitor DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION. TYPES: BEGIN OF ty_health_status, component TYPE string, status TYPE string, message TYPE string, timestamp TYPE timestamp, memory_percent TYPE i, cpu_percent TYPE i, END OF ty_health_status.
METHODS: get_current_health RETURNING VALUE(rs_status) TYPE ty_health_status.
METHODS: check_and_alert RAISING cx_failed.
PRIVATE SECTION. CONSTANTS: gc_memory_threshold TYPE i VALUE 85, gc_cpu_threshold TYPE i VALUE 80.
ENDCLASS.
CLASS zcl_health_monitor IMPLEMENTATION.
METHOD get_current_health. " Timestamp setzen GET TIME STAMP FIELD rs_status-timestamp. rs_status-component = 'ABAP_ENVIRONMENT'.
" Memory-Status aus System-Info " In ABAP Cloud: cl_abap_context_info fuer Basis-Infos DATA(lv_zone) = cl_abap_context_info=>get_system_context( )-zone_id. rs_status-message = |System Zone: { lv_zone }|.
" Fuer detaillierte Metriken: SAP BTP APIs nutzen " Diese sind ueber Cloud Foundry bzw. BTP Service verfuegbar rs_status-status = 'HEALTHY'. rs_status-memory_percent = 72. " Beispielwert rs_status-cpu_percent = 45. " Beispielwert ENDMETHOD.
METHOD check_and_alert. DATA(ls_health) = get_current_health( ).
" Memory-Check IF ls_health-memory_percent > gc_memory_threshold. " Alert senden (via Application Logging oder Event) DATA(lo_log) = cl_bali_log=>create_with_header( header = cl_bali_header_setter=>create( object = 'ZSYSTEM' subobject = 'HEALTH' external_id = |HEALTH_CHECK_{ ls_health-timestamp }| ) ).
lo_log->add_item( cl_bali_message_setter=>create( severity = if_bali_constants=>c_severity_warning text = |High memory usage: { ls_health-memory_percent }%| ) ).
lo_log->save( ). ENDIF.
" CPU-Check IF ls_health-cpu_percent > gc_cpu_threshold. " Analog fuer CPU ENDIF. ENDMETHOD.
ENDCLASS.Performance-Analyse und SQL Trace
SQL Trace Analysis App
Die Fiori App “SQL Trace Analysis” (App-ID: F2912) ersetzt den klassischen ST05 SQL Trace:
┌────────────────────────────────────────────────────────────────────────────┐│ SQL Trace Analysis ││ ││ ┌─────────────────────────────────────────────────────────────────────────┐│ │ Active Traces ││ │ ││ │ User Started Duration Status ││ │ DEVELOPER01 14:23:15 00:05:23 ● Recording ││ │ TESTUSER 13:45:00 00:30:00 ○ Stopped ││ │ ││ │ [Start New Trace] [Stop All] [Delete Selected] ││ └─────────────────────────────────────────────────────────────────────────┘│ ││ ┌─────────────────────────────────────────────────────────────────────────┐│ │ Trace Results: DEVELOPER01 ││ │ ││ │ Duration Records Statement ││ │ ───────────────────────────────────────────────────────────────────── ││ │ 1.234 ms 1,500 SELECT * FROM ZCUSTOMER WHERE ... ││ │ 0.892 ms 250 SELECT * FROM ZORDERS WHERE CUSTOMER_ID = ... ││ │ 0.456 ms 50 SELECT * FROM ZITEMS WHERE ORDER_ID = ... ││ │ 0.123 ms 1 UPDATE ZCUSTOMER SET LAST_ACCESS = ... ││ │ ││ │ Total: 4 statements, 2.705 ms, 1,801 records ││ └─────────────────────────────────────────────────────────────────────────┘└────────────────────────────────────────────────────────────────────────────┘Programmtischer SQL Trace
" SQL Trace programmtisch steuernCLASS zcl_sql_trace_helper DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION. METHODS: start_trace IMPORTING iv_user TYPE syuname DEFAULT sy-uname RAISING cx_failed.
stop_trace IMPORTING iv_user TYPE syuname DEFAULT sy-uname RAISING cx_failed.
analyze_trace IMPORTING iv_user TYPE syuname DEFAULT sy-uname RETURNING VALUE(rt_results) TYPE string_table.
ENDCLASS.
CLASS zcl_sql_trace_helper IMPLEMENTATION.
METHOD start_trace. " In ABAP Cloud: Trace ueber Fiori App starten " Programmtisch: cl_abap_sql_trace API (wenn verfuegbar)
" Alternative: ABAP SQL Performance Hints direkt im Code " SELECT ... %_HINTS HANAODBC 'RESULT_CACHE' ENDMETHOD.
METHOD stop_trace. " Trace stoppen ENDMETHOD.
METHOD analyze_trace. " Trace-Ergebnisse analysieren " In produktivem Code: Ergebnisse aus Trace-API lesen ENDMETHOD.
ENDCLASS.Performance-Analyse Best Practices
" Performance-kritische Abfragen optimierenCLASS zcl_performance_analyzer DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION. METHODS: analyze_slow_queries RETURNING VALUE(rt_recommendations) TYPE string_table.
ENDCLASS.
CLASS zcl_performance_analyzer IMPLEMENTATION.
METHOD analyze_slow_queries. " Haeufige Performance-Probleme und Loesungen
" 1. Fehlende Indizes APPEND |Problem: Full Table Scan auf ZCUSTOMER| TO rt_recommendations. APPEND |Loesung: Secondary Index auf Suchfelder anlegen| TO rt_recommendations.
" 2. SELECT * vermeiden APPEND |Problem: SELECT * FROM large_table| TO rt_recommendations. APPEND |Loesung: Nur benoetigte Felder selektieren| TO rt_recommendations.
" Beispiel: Optimierte Abfrage " Schlecht: " SELECT * FROM zcustomer INTO TABLE @DATA(lt_all).
" Gut: SELECT customer_id, name, city FROM zcustomer WHERE region = @lv_region INTO TABLE @DATA(lt_customers).
" 3. N+1 Query Problem vermeiden APPEND |Problem: Schleifen mit Einzelabfragen| TO rt_recommendations. APPEND |Loesung: JOINs oder FOR ALL ENTRIES nutzen| TO rt_recommendations.
" Schlecht: " LOOP AT lt_orders INTO DATA(ls_order). " SELECT SINGLE * FROM zcustomer WHERE id = ls_order-customer_id. " ENDLOOP.
" Gut: IF lt_orders IS NOT INITIAL. SELECT customer_id, name FROM zcustomer FOR ALL ENTRIES IN @lt_orders WHERE customer_id = @lt_orders-customer_id INTO TABLE @DATA(lt_customers_opt). ENDIF.
" 4. CDS View Aggregationen nutzen APPEND |Problem: Aggregation in ABAP-Loop| TO rt_recommendations. APPEND |Loesung: Aggregation in CDS View oder SQL| TO rt_recommendations. ENDMETHOD.
ENDCLASS.EXPLAIN PLAN Analyse
-- CDS View Performance analysieren@AbapCatalog.sqlViewName: 'ZV_ORDER_STATS'@Analytics.dataCategory: #CUBEdefine view entity ZI_OrderStatistics as select from zorder as Order association [1..1] to ZI_Customer as _Customer on $projection.CustomerId = _Customer.CustomerId{ key Order.order_id as OrderId, Order.customer_id as CustomerId, Order.order_date as OrderDate,
-- Aggregierbare Measures @Aggregation.default: #SUM Order.total_amount as TotalAmount,
@Aggregation.default: #COUNT cast(1 as abap.int4) as OrderCount,
-- Association fuer Join _Customer}Job Monitoring
Fiori App: Application Jobs
Die App “Application Jobs” (App-ID: F3544) zeigt alle geplanten und ausgefuehrten Jobs:
┌────────────────────────────────────────────────────────────────────────────┐│ Application Jobs ││ ││ Filter: [All Jobs ▼] Status: [All ▼] Date: [Today ▼] [Search] ││ ││ ┌─────────────────────────────────────────────────────────────────────────┐│ │ Job Name Template Status Start/End ││ │ ───────────────────────────────────────────────────────────────────── ││ │ Z_DAILY_CLEANUP_001 Z_DAILY_CLEANUP ✓ Finished 06:00 - 06:15 ││ │ Z_REPORT_GEN_002 Z_REPORT_GEN ✓ Finished 07:00 - 07:45 ││ │ Z_DATA_SYNC_003 Z_DATA_SYNC ● Running 08:00 - ... ││ │ Z_MONTHLY_ARCH_004 Z_MONTHLY_ARCH ○ Scheduled 01.03.2026 00:00 ││ │ Z_FAILED_TASK_005 Z_DATA_IMPORT ✗ Failed 09:00 - 09:02 ││ │ ││ │ [View Log] [Restart] [Cancel] [Schedule New] ││ └─────────────────────────────────────────────────────────────────────────┘│ ││ Job Details: Z_FAILED_TASK_005 ││ ┌─────────────────────────────────────────────────────────────────────────┐│ │ Error Message: ││ │ CX_SY_OPEN_SQL_DB: Database error 1234 at SELECT from ZDATA_SOURCE ││ │ ││ │ Application Log: ││ │ 09:00:01 - Job started ││ │ 09:00:15 - Processing batch 1/10 ││ │ 09:02:03 - ERROR: Connection to source system lost ││ │ 09:02:03 - Job terminated with error ││ └─────────────────────────────────────────────────────────────────────────┘└────────────────────────────────────────────────────────────────────────────┘Job-Status Uebersicht
| Status | Beschreibung | Aktion erforderlich |
|---|---|---|
| Scheduled | Job ist geplant | Keine |
| Ready | Job wartet auf Ausfuehrung | Keine |
| Running | Job laeuft aktuell | Monitoring |
| Finished | Job erfolgreich beendet | Log pruefen |
| Failed | Job mit Fehler beendet | Fehler analysieren |
| Canceled | Job manuell abgebrochen | Ursache pruefen |
Programmtisches Job-Monitoring
" Job-Monitoring Klasse fuer ABAP CloudCLASS zcl_job_monitor DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION. TYPES: BEGIN OF ty_job_info, job_name TYPE cl_apj_rt_api=>ty_job_name, job_count TYPE cl_apj_rt_api=>ty_job_count, status TYPE string, start_timestamp TYPE timestamp, end_timestamp TYPE timestamp, has_errors TYPE abap_bool, END OF ty_job_info, ty_job_infos TYPE STANDARD TABLE OF ty_job_info WITH KEY job_name job_count.
METHODS: get_jobs_by_template IMPORTING iv_template TYPE cl_apj_rt_api=>ty_template_name iv_from_date TYPE d DEFAULT sy-datum - 7 RETURNING VALUE(rt_jobs) TYPE ty_job_infos.
METHODS: get_failed_jobs IMPORTING iv_from_date TYPE d DEFAULT sy-datum RETURNING VALUE(rt_jobs) TYPE ty_job_infos.
METHODS: get_job_log IMPORTING iv_job_name TYPE cl_apj_rt_api=>ty_job_name iv_job_count TYPE cl_apj_rt_api=>ty_job_count RETURNING VALUE(rt_log) TYPE string_table.
METHODS: restart_failed_job IMPORTING iv_job_name TYPE cl_apj_rt_api=>ty_job_name iv_job_count TYPE cl_apj_rt_api=>ty_job_count RAISING cx_apj_rt.
ENDCLASS.
CLASS zcl_job_monitor IMPLEMENTATION.
METHOD get_jobs_by_template. " Job-Liste aus Runtime API abrufen TRY. " Job-Katalog durchsuchen DATA(lt_job_catalog) = cl_apj_rt_api=>get_job_catalog( ).
LOOP AT lt_job_catalog INTO DATA(ls_job) WHERE template_name = iv_template.
" Job-Details abrufen DATA(ls_job_details) = cl_apj_rt_api=>get_job_details( iv_job_name = ls_job-job_name iv_job_count = ls_job-job_count ).
" Zu Ergebnis hinzufuegen APPEND VALUE #( job_name = ls_job-job_name job_count = ls_job-job_count status = ls_job_details-status start_timestamp = ls_job_details-start_timestamp end_timestamp = ls_job_details-end_timestamp has_errors = xsdbool( ls_job_details-status = 'F' ) ) TO rt_jobs. ENDLOOP.
CATCH cx_apj_rt INTO DATA(lx_error). " Fehler behandeln RETURN. ENDTRY. ENDMETHOD.
METHOD get_failed_jobs. " Fehlgeschlagene Jobs ermitteln TRY. DATA(lt_all_jobs) = cl_apj_rt_api=>get_job_catalog( ).
LOOP AT lt_all_jobs INTO DATA(ls_job). DATA(ls_details) = cl_apj_rt_api=>get_job_details( iv_job_name = ls_job-job_name iv_job_count = ls_job-job_count ).
" Nur fehlgeschlagene Jobs IF ls_details-status = 'A'. " Aborted/Failed APPEND VALUE #( job_name = ls_job-job_name job_count = ls_job-job_count status = 'FAILED' start_timestamp = ls_details-start_timestamp end_timestamp = ls_details-end_timestamp has_errors = abap_true ) TO rt_jobs. ENDIF. ENDLOOP.
CATCH cx_apj_rt. RETURN. ENDTRY. ENDMETHOD.
METHOD get_job_log. " Job-Log abrufen TRY. DATA(lt_messages) = cl_apj_rt_api=>get_job_log( iv_job_name = iv_job_name iv_job_count = iv_job_count ).
LOOP AT lt_messages INTO DATA(ls_msg). APPEND |{ ls_msg-timestamp } - { ls_msg-severity }: { ls_msg-text }| TO rt_log. ENDLOOP.
CATCH cx_apj_rt. APPEND 'Log nicht verfuegbar' TO rt_log. ENDTRY. ENDMETHOD.
METHOD restart_failed_job. " Fehlgeschlagenen Job erneut starten " Hinweis: Der Job muss neu eingeplant werden cl_apj_rt_api=>restart_job( iv_job_name = iv_job_name iv_job_count = iv_job_count ). ENDMETHOD.
ENDCLASS.Job-Template mit Monitoring
" Job-Template-Klasse mit integriertem MonitoringCLASS zcl_monitored_job DEFINITION PUBLIC FINAL CREATE PUBLIC.
INTERFACES if_apj_dt_exec_object. INTERFACES if_apj_rt_exec_object.
PUBLIC SECTION. TYPES: BEGIN OF ty_job_parameters, source_system TYPE string, batch_size TYPE i, END OF ty_job_parameters.
PRIVATE SECTION. DATA: mo_log TYPE REF TO if_bali_log, mv_job_name TYPE string, ms_params TYPE ty_job_parameters, mv_start_time TYPE timestamp.
METHODS: init_logging, log_progress IMPORTING iv_message TYPE string iv_severity TYPE if_bali_constants=>ty_severity DEFAULT if_bali_constants=>c_severity_status, finalize_logging IMPORTING iv_success TYPE abap_bool.
ENDCLASS.
CLASS zcl_monitored_job IMPLEMENTATION.
METHOD if_apj_dt_exec_object~get_parameters. " Parameter-Definition fuer Job-Template et_parameter_def = VALUE #( ( selname = 'P_SOURCE' kind = 'P' datatype = 'STRING' component_type = 'SOURCE_SYSTEM' ) ( selname = 'P_BATCH' kind = 'P' datatype = 'INT4' component_type = 'BATCH_SIZE' ) ). ENDMETHOD.
METHOD if_apj_rt_exec_object~execute. " Job-Ausfuehrung mit Monitoring init_logging( ).
GET TIME STAMP FIELD mv_start_time. log_progress( |Job gestartet| ).
TRY. " Parameter auslesen LOOP AT it_parameters INTO DATA(ls_param). CASE ls_param-selname. WHEN 'P_SOURCE'. ms_params-source_system = ls_param-low. WHEN 'P_BATCH'. ms_params-batch_size = ls_param-low. ENDCASE. ENDLOOP.
log_progress( |Parameter: Source={ ms_params-source_system }, Batch={ ms_params-batch_size }| ).
" Hauptverarbeitung DATA(lv_processed) = 0. DATA(lv_total) = 1000. " Beispiel
WHILE lv_processed < lv_total. " Batch verarbeiten lv_processed = lv_processed + ms_params-batch_size.
" Fortschritt loggen DATA(lv_percent) = lv_processed * 100 / lv_total. log_progress( |Fortschritt: { lv_percent }% ({ lv_processed }/{ lv_total })| ).
" Kurze Pause um System nicht zu ueberlasten " (in echtem Code: COMMIT WORK AND WAIT verwenden) ENDWHILE.
log_progress( |Verarbeitung abgeschlossen. { lv_processed } Datensaetze.| ). finalize_logging( iv_success = abap_true ).
CATCH cx_root INTO DATA(lx_error). log_progress( iv_message = |Fehler: { lx_error->get_text( ) }| iv_severity = if_bali_constants=>c_severity_error ). finalize_logging( iv_success = abap_false ). RAISE EXCEPTION lx_error. ENDTRY. ENDMETHOD.
METHOD init_logging. " Application Log initialisieren TRY. mo_log = cl_bali_log=>create_with_header( header = cl_bali_header_setter=>create( object = 'ZJOB' subobject = 'MONITOR' external_id = |JOB_{ sy-datum }_{ sy-uzeit }| ) ). CATCH cx_bali_runtime. " Log-Initialisierung fehlgeschlagen ENDTRY. ENDMETHOD.
METHOD log_progress. CHECK mo_log IS BOUND.
TRY. mo_log->add_item( cl_bali_message_setter=>create( severity = iv_severity text = iv_message ) ). CATCH cx_bali_runtime. " Log-Eintrag fehlgeschlagen ENDTRY. ENDMETHOD.
METHOD finalize_logging. CHECK mo_log IS BOUND.
TRY. " Laufzeit berechnen GET TIME STAMP FIELD DATA(lv_end_time). DATA(lv_duration) = cl_abap_tstmp=>subtract( tstmp1 = lv_end_time tstmp2 = mv_start_time ).
" Abschluss-Nachricht IF iv_success = abap_true. log_progress( |Job erfolgreich beendet. Laufzeit: { lv_duration } Sekunden| ). ELSE. log_progress( iv_message = |Job mit Fehler beendet. Laufzeit: { lv_duration } Sekunden| iv_severity = if_bali_constants=>c_severity_error ). ENDIF.
" Log speichern mo_log->save( ).
CATCH cx_bali_runtime. " Log-Speicherung fehlgeschlagen ENDTRY. ENDMETHOD.
ENDCLASS.ABAP Runtime Errors
Fiori App: ABAP Runtime Errors
Diese App ersetzt ST22 und zeigt Runtime-Fehler (Dumps):
┌────────────────────────────────────────────────────────────────────────────┐│ ABAP Runtime Errors ││ ││ Filter: Date [14.02.2026] User [All] Error Type [All] [Apply] ││ ││ ┌─────────────────────────────────────────────────────────────────────────┐│ │ Time User Error Type Program ││ │ ───────────────────────────────────────────────────────────────────── ││ │ 10:45:23 DEVELOPER01 COMPUTE_INT_ZERODIVIDE ZCL_CALCULATOR ││ │ 09:12:05 TESTUSER OBJECTS_OBJREF_NOT_ASSIGNED ZCL_PROCESSOR ││ │ 08:30:17 BATCHUSER DBSQL_SQL_ERROR ZCL_DATA_LOADER ││ │ ││ │ [View Details] [Download] [Export to CSV] ││ └─────────────────────────────────────────────────────────────────────────┘│ ││ Error Details: COMPUTE_INT_ZERODIVIDE ││ ┌─────────────────────────────────────────────────────────────────────────┐│ │ Exception: CX_SY_ZERODIVIDE ││ │ Message: Division by zero ││ │ ││ │ Source Position: ││ │ Class: ZCL_CALCULATOR Method: DIVIDE Line: 45 ││ │ ││ │ Variables: ││ │ LV_NUMERATOR = 100 ││ │ LV_DENOMINATOR = 0 ││ │ ││ │ Call Stack: ││ │ 1. ZCL_CALCULATOR=>DIVIDE ││ │ 2. ZCL_ORDER_SERVICE=>CALCULATE_DISCOUNT ││ │ 3. ZCL_ORDER_PROCESSOR=>PROCESS ││ └─────────────────────────────────────────────────────────────────────────┘└────────────────────────────────────────────────────────────────────────────┘Exception Handling Best Practices
" Robustes Exception Handling fuer Monitoring-freundlichen CodeCLASS zcl_robust_processor DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION. METHODS: process_data IMPORTING it_data TYPE ty_data_tab RAISING zcx_processing_error.
PRIVATE SECTION. METHODS: log_exception IMPORTING ix_error TYPE REF TO cx_root.
ENDCLASS.
CLASS zcl_robust_processor IMPLEMENTATION.
METHOD process_data. LOOP AT it_data INTO DATA(ls_data). TRY. " Verarbeitung mit moeglichen Exceptions process_single_item( ls_data ).
CATCH cx_sy_zerodivide INTO DATA(lx_zerodiv). " Spezifische Behandlung log_exception( lx_zerodiv ). " Weitermachen mit naechstem Datensatz
CATCH cx_sy_open_sql_db INTO DATA(lx_db). " Datenbankfehler - kritisch log_exception( lx_db ). RAISE EXCEPTION TYPE zcx_processing_error EXPORTING textid = zcx_processing_error=>database_error previous = lx_db.
CATCH cx_root INTO DATA(lx_other). " Unerwarteter Fehler log_exception( lx_other ). RAISE EXCEPTION TYPE zcx_processing_error EXPORTING textid = zcx_processing_error=>unexpected_error previous = lx_other. ENDTRY. ENDLOOP. ENDMETHOD.
METHOD log_exception. " Exception fuer spaetere Analyse loggen TRY. DATA(lo_log) = cl_bali_log=>create_with_header( header = cl_bali_header_setter=>create( object = 'ZERROR' subobject = 'EXCEPTION' external_id = |{ sy-datum }_{ sy-uzeit }| ) ).
" Exception-Details lo_log->add_item( cl_bali_exception_setter=>create( exception = ix_error ) ).
" Zusatzinformationen lo_log->add_item( cl_bali_message_setter=>create( severity = if_bali_constants=>c_severity_error text = |User: { sy-uname }, Program: { sy-repid }| ) ).
lo_log->save( ).
CATCH cx_bali_runtime. " Logging fehlgeschlagen - ignorieren ENDTRY. ENDMETHOD.
ENDCLASS.Custom Monitoring Dashboard
CDS View fuer Monitoring-Daten
-- Monitoring-View fuer Dashboard@AbapCatalog.sqlViewName: 'ZV_SYS_MONITOR'@Analytics.dataCategory: #CUBE@AccessControl.authorizationCheck: #NOT_REQUIREDdefine view entity ZI_SystemMonitoring as select from zbali_log as Log association [0..*] to ZI_ApplicationJobs as _Jobs on $projection.ExternalId = _Jobs.RelatedLogId{ key Log.log_handle as LogHandle, Log.external_id as ExternalId, Log.object as LogObject, Log.subobject as LogSubobject,
@Semantics.systemDateTime.createdAt: true Log.log_timestamp as LogTimestamp,
@Aggregation.default: #COUNT cast(1 as abap.int4) as LogCount,
case Log.max_severity when 'E' then 'Error' when 'W' then 'Warning' when 'I' then 'Info' when 'S' then 'Success' else 'Unknown' end as SeverityText,
-- Associations _Jobs}where Log.log_timestamp >= $session.system_date - 7Monitoring Report
" Monitoring Report fuer taegliche PruefungCLASS zcl_daily_monitoring_report DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION. METHODS: generate_report RETURNING VALUE(rs_report) TYPE string.
PRIVATE SECTION. METHODS: check_failed_jobs RETURNING VALUE(rt_issues) TYPE string_table.
METHODS: check_runtime_errors RETURNING VALUE(rt_issues) TYPE string_table.
METHODS: check_application_logs RETURNING VALUE(rt_issues) TYPE string_table.
ENDCLASS.
CLASS zcl_daily_monitoring_report IMPLEMENTATION.
METHOD generate_report. DATA: lt_all_issues TYPE string_table.
" Zeitstempel rs_report = |=== Daily Monitoring Report ===\n|. rs_report = rs_report && |Datum: { sy-datum DATE = USER }\n|. rs_report = rs_report && |Zeit: { sy-uzeit TIME = USER }\n\n|.
" Job-Pruefung rs_report = rs_report && |--- Background Jobs ---\n|. DATA(lt_job_issues) = check_failed_jobs( ). IF lt_job_issues IS INITIAL. rs_report = rs_report && |Keine fehlgeschlagenen Jobs\n\n|. ELSE. LOOP AT lt_job_issues INTO DATA(lv_issue). rs_report = rs_report && |! { lv_issue }\n|. ENDLOOP. rs_report = rs_report && |\n|. ENDIF.
" Runtime Errors rs_report = rs_report && |--- Runtime Errors ---\n|. DATA(lt_error_issues) = check_runtime_errors( ). IF lt_error_issues IS INITIAL. rs_report = rs_report && |Keine Runtime Errors\n\n|. ELSE. LOOP AT lt_error_issues INTO lv_issue. rs_report = rs_report && |! { lv_issue }\n|. ENDLOOP. rs_report = rs_report && |\n|. ENDIF.
" Application Logs rs_report = rs_report && |--- Application Logs ---\n|. DATA(lt_log_issues) = check_application_logs( ). IF lt_log_issues IS INITIAL. rs_report = rs_report && |Keine kritischen Log-Eintraege\n\n|. ELSE. LOOP AT lt_log_issues INTO lv_issue. rs_report = rs_report && |! { lv_issue }\n|. ENDLOOP. ENDIF.
" Zusammenfassung DATA(lv_total) = lines( lt_job_issues ) + lines( lt_error_issues ) + lines( lt_log_issues ). rs_report = rs_report && |\n=== Zusammenfassung ===\n|. rs_report = rs_report && |Gefundene Probleme: { lv_total }\n|.
IF lv_total = 0. rs_report = rs_report && |Status: GRUEN - Keine Aktionen erforderlich\n|. ELSEIF lv_total < 5. rs_report = rs_report && |Status: GELB - Pruefung empfohlen\n|. ELSE. rs_report = rs_report && |Status: ROT - Sofortige Aufmerksamkeit erforderlich\n|. ENDIF. ENDMETHOD.
METHOD check_failed_jobs. " Fehlgeschlagene Jobs der letzten 24 Stunden pruefen DATA(lo_monitor) = NEW zcl_job_monitor( ). DATA(lt_failed) = lo_monitor->get_failed_jobs( iv_from_date = sy-datum - 1 ).
LOOP AT lt_failed INTO DATA(ls_job). APPEND |Job { ls_job-job_name } fehlgeschlagen um { ls_job-start_timestamp }| TO rt_issues. ENDLOOP. ENDMETHOD.
METHOD check_runtime_errors. " Runtime Errors aus Application Log pruefen " In ABAP Cloud: Keine direkte SNAP-Tabelle, stattdessen BALI_LOG TRY. DATA(lt_filter) = VALUE if_bali_log_filter=>ty_t_selector( ( sign = 'I' option = 'EQ' low = 'ZERROR' ) ).
DATA(lt_logs) = cl_bali_log_db=>get_instance( )->load_logs_via_filter( filter = cl_bali_log_filter=>create( )->set_subobject( lt_filter ) ).
LOOP AT lt_logs INTO DATA(lo_log). DATA(ls_header) = lo_log->get_header( ). APPEND |Runtime Error: { ls_header-external_id }| TO rt_issues. ENDLOOP.
CATCH cx_bali_runtime. RETURN. ENDTRY. ENDMETHOD.
METHOD check_application_logs. " Kritische Log-Eintraege pruefen TRY. " Logs mit Errors der letzten 24 Stunden DATA(lt_logs) = cl_bali_log_db=>get_instance( )->load_logs_via_filter( filter = cl_bali_log_filter=>create( )->set_maximum_severity( if_bali_constants=>c_severity_error ) ).
LOOP AT lt_logs INTO DATA(lo_log). DATA(ls_header) = lo_log->get_header( ). APPEND |Log { ls_header-object }/{ ls_header-subobject }: { ls_header-external_id }| TO rt_issues. ENDLOOP.
CATCH cx_bali_runtime. RETURN. ENDTRY. ENDMETHOD.
ENDCLASS.Wichtige Monitoring-Apps Uebersicht
| App-ID | App Name | Zweck | URL-Pfad |
|---|---|---|---|
| F5687 | Health Monitoring | Systemgesundheit | /sap/bc/ui5_ui5/sap/healthmonitoring |
| F2912 | SQL Trace Analysis | Performance | /sap/bc/ui5_ui5/sap/sqltrace |
| F3544 | Application Jobs | Job-Ueberwachung | /sap/bc/ui5_ui5/sap/applicationjobs |
| F3840 | Manage Background Tasks | bgPF Tasks | /sap/bc/ui5_ui5/sap/bgpf |
| F1734 | Application Logs | Log-Analyse | /sap/bc/ui5_ui5/sap/applicationlogs |
| - | ABAP Runtime Errors | Dump-Analyse | /sap/bc/ui5_ui5/sap/runtimeerrors |
Best Practices
Monitoring-Strategie
| Bereich | Empfehlung | Frequenz |
|---|---|---|
| Health Check | Automatisierte Pruefung | Alle 5 Minuten |
| Job Monitoring | Fehlgeschlagene Jobs pruefen | Taeglich |
| Performance | SQL Trace bei Problemen | Bei Bedarf |
| Logs | Kritische Logs pruefen | Taeglich |
| Runtime Errors | Dumps analysieren | Bei Auftreten |
| Kapazitaet | Resource Usage pruefen | Woechentlich |
Alerting Best Practices
- Schwellwerte definieren: Klare Grenzwerte fuer Memory, CPU, Response Time
- Eskalationsstufen: Warning → Error → Critical mit unterschiedlichen Benachrichtigungen
- False Positives vermeiden: Mindestdauer vor Alert (z.B. 5 Minuten sustained high CPU)
- Dokumentation: Runbooks fuer jeden Alert-Typ erstellen
- Regelmaessige Review: Alert-Schwellwerte quartalsweise pruefen
Weiterfuehrende Themen
- Application Logging - Detaillierte Logging-Implementierung
- Background Jobs - Job-Scheduling und -Verwaltung
- ABAP Unit Testing - Tests fuer stabilen Code
- Performance Optimization - Code-Optimierung
Zusammenfassung
ABAP Environment Monitoring auf SAP BTP erfordert einen anderen Ansatz als On-Premise:
- Fiori Apps statt klassischer Transaktionen (SM21, ST22, SM37)
- Application Logging (BALI) fuer persistente Protokollierung
- cl_apj_rt_api fuer programmtisches Job-Monitoring
- SAP Cloud ALM fuer Enterprise-weites Monitoring und Alerting
- CDS Views fuer eigene Monitoring-Dashboards
Die Kombination aus Standard-Fiori-Apps, programmtischem Monitoring und Cloud ALM ermoeglicht eine umfassende Ueberwachung deines ABAP Cloud Systems.