ABAP Environment Monitoring auf SAP BTP

kategorie
DevOps
Veröffentlicht
autor
Johannes

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:

ToolZweckZielgruppe
SAP BTP CockpitInfrastruktur-MonitoringCloud Administrator
Fiori App: Health MonitoringSystemgesundheitABAP Administrator
Fiori App: SQL Trace AnalysisPerformance-DiagnoseEntwickler/Admin
Fiori App: ABAP Runtime ErrorsFehleranalyseEntwickler
Fiori App: Manage Background TasksJob-UeberwachungAdministrator
Application JobsJob-Scheduling und StatusAdministrator
Application LogsProtokoll-AnalyseEntwickler/Admin
SAP Cloud ALMEnterprise MonitoringIT 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

MetrikBeschreibungKritischer Schwellwert
Memory UsageSpeicherauslastung des ABAP Systems> 90%
CPU UsageProzessorauslastung> 85% sustained
DB ConnectionsAktive Datenbankverbindungen> 80% des Limits
Work ProcessesVerfuegbare Dialog/Background WPs< 20% frei
Response TimeDurchschnittliche Antwortzeit> 2 Sekunden
Active SessionsAngemeldete Benutzer> 80% des Limits

Alerting mit SAP Cloud ALM

" Programmtisches Alert-Monitoring ueber API
CLASS 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 steuern
CLASS 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 optimieren
CLASS 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: #CUBE
define 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

StatusBeschreibungAktion erforderlich
ScheduledJob ist geplantKeine
ReadyJob wartet auf AusfuehrungKeine
RunningJob laeuft aktuellMonitoring
FinishedJob erfolgreich beendetLog pruefen
FailedJob mit Fehler beendetFehler analysieren
CanceledJob manuell abgebrochenUrsache pruefen

Programmtisches Job-Monitoring

" Job-Monitoring Klasse fuer ABAP Cloud
CLASS 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 Monitoring
CLASS 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 Code
CLASS 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_REQUIRED
define 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 - 7

Monitoring Report

" Monitoring Report fuer taegliche Pruefung
CLASS 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-IDApp NameZweckURL-Pfad
F5687Health MonitoringSystemgesundheit/sap/bc/ui5_ui5/sap/healthmonitoring
F2912SQL Trace AnalysisPerformance/sap/bc/ui5_ui5/sap/sqltrace
F3544Application JobsJob-Ueberwachung/sap/bc/ui5_ui5/sap/applicationjobs
F3840Manage Background TasksbgPF Tasks/sap/bc/ui5_ui5/sap/bgpf
F1734Application LogsLog-Analyse/sap/bc/ui5_ui5/sap/applicationlogs
-ABAP Runtime ErrorsDump-Analyse/sap/bc/ui5_ui5/sap/runtimeerrors

Best Practices

Monitoring-Strategie

BereichEmpfehlungFrequenz
Health CheckAutomatisierte PruefungAlle 5 Minuten
Job MonitoringFehlgeschlagene Jobs pruefenTaeglich
PerformanceSQL Trace bei ProblemenBei Bedarf
LogsKritische Logs pruefenTaeglich
Runtime ErrorsDumps analysierenBei Auftreten
KapazitaetResource Usage pruefenWoechentlich

Alerting Best Practices

  1. Schwellwerte definieren: Klare Grenzwerte fuer Memory, CPU, Response Time
  2. Eskalationsstufen: Warning → Error → Critical mit unterschiedlichen Benachrichtigungen
  3. False Positives vermeiden: Mindestdauer vor Alert (z.B. 5 Minuten sustained high CPU)
  4. Dokumentation: Runbooks fuer jeden Alert-Typ erstellen
  5. Regelmaessige Review: Alert-Schwellwerte quartalsweise pruefen

Weiterfuehrende Themen

Zusammenfassung

ABAP Environment Monitoring auf SAP BTP erfordert einen anderen Ansatz als On-Premise:

  1. Fiori Apps statt klassischer Transaktionen (SM21, ST22, SM37)
  2. Application Logging (BALI) fuer persistente Protokollierung
  3. cl_apj_rt_api fuer programmtisches Job-Monitoring
  4. SAP Cloud ALM fuer Enterprise-weites Monitoring und Alerting
  5. 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.