
ABAP - XCO Logging
Die XCO Klassen sind Bestandteil der ABAP Cloud APIs und verfügen über zahlreiche Funktionen, die nicht immer so einfach zu verstehen sind. In diesem Artikel schauen wir uns das Logging Objekt im Detail an.
Inhaltsverzeichnis
Die XCO Klassen sind Hilfsklassen die verschiedene Funktionen des Alltags gebündelt unter einer öffentlichen API zur Verfügung stellen. Weitere Informationen und eine Übersicht über die XCO Bibliotheken findest du auf der Übersichtsseite.
Einleitung
Im Bereich der XCO Klassen gibt es ebenfalls ein Logging Objekt für Meldungen und andere Objekte. Daher lohnt sich ein Vergleich der verschiedenen Klassen und wie wir diese für uns nutzen können. Im Grunde verschalt das Framework die BAL_LOG* Funktionsbausteine in den Klassen. Am Ende des Artikels findest du einen Vergleich der Klassen und Frameworks, um für dich das Beste Ergebnis zu finden.
Vorbereitung
Damit wir gleich unsere Testfälle durchprozessieren können, legen wir uns im ersten Schritt ein Logging Objekt ZBS_XCO_LOG und ein entsprechendes Unterobjekt an. Da wir mit dem Application Log arbeiten, brauchen wir die ID für die weitere Verarbeitung.
Damit wir auch entsprechende echte Nachrichten anlegen können, benötigen wir eine Nachrichtenklasse mit ein paar Dummy Meldungen für das Log.
Zum Abschluss benötigst du auch Berechtigungen für das Application Log, wenn du zum Beispiel in einem Cloud System arbeitest. Hier sind die Abgrenzungen sehr streng und um an die Logs und Meldungen zu kommen, aber auch um sie zu schreiben, benötigen wir S_APPL_LOG für unser neues Objekt. Im Paket findest du dafür eine IAM App mit Business Catalog.
Erstellung
Schauen wir uns einmal die Erstellung eines Application Logs an. Dazu legen wir über die Klasse XCO_CP_BAL und die entsprechende Factory ein neues Log Objekt an. Da in der Implementierung bereits ein Header erzeugt wird, benötigst du auch hier bereits die Berechtigungen für das Application Log Objekt. Wir übergeben das Objekt, Subobjekt und eine externe ID, die wir für die Suche und zur Identifikation verwenden können.
DATA(log) = xco_cp_bal=>for->database(
)->log->create( iv_object = 'ZBS_XCO_LOG'
iv_subobject = 'TEST'
iv_external_id = external_id ).
Im Beispiel oben verwenden wir DATABASE als Persistenz, hier hast du aktuell zwei Möglichkeiten zur Auswahl:
- DATABASE - Die Meldungen werden auf der Datenbank gespeichert.
- MEMORY - Die Meldungen werden nur zur Laufzeit im Speicher gehalten.
Im nächsten Schritt wollen wir direkt Meldungen an das Objekt übergeben. Dazu bietet uns das Objekt verschiedene Methoden an, die wir verwenden können. Der Fokus liegt allerdings auf Objekten aus dem XCO Bereich.
Übergeben wir nun eine Nachricht, eine Ausnahme und ein Objekt mit dem Interface für News und Text an das Log Objekt. Weitere Details zu den Hilfsmethoden findest du in Git.
log->add_message( get_message( )->value ).
log->add_exception( NEW cx_sy_itab_line_not_found( ) ).
log->add_news( get_strings( ) ).
log->add_text( get_strings( ) ).
Damit wäre auch schon die Implementierung fertig. Da wir als Persistenz die Datenbank verwendet haben, werden alle Nachrichten direkt auf die Datenbank geschrieben. Dabei wird ein Commit über eine zweite Datenbankverbindung ausgelöst, was den aktuellen Prozess nicht beeinflusst. Damit kannst du später auch auf die Meldungen zugreifen, wenn dein eigentlicher Prozess abgebrochen ist. Damit ist auch ein Aufruf einer Speichern-Methode nicht mehr notwendig.
Lesen
Versuchen wir nun die verschiedenen Meldungen wieder zu lesen. Dazu gehen wir wieder über die entsprechende Persistenz und laden über den Handle das Log. Das Handle findest du als Attribut am Log Objekt.
DATA(log) = xco_cp_bal=>for->database( )->log->load( handle ).
Über das Message Attribut können wir uns dann alle Instanzen der Meldungen geben lassen. In jeder Message stehen dann drei Informationen zur Verfügung, die eigentliche Nachricht, das Level der Details, wenn du die Meldungen auch entsprechend klassifiziert hast und die der Zeitstempel der Nachricht, wenn du weitere Informationen zum Auftreten der Meldung benötigst.
LOOP AT log->messages->all->get( ) INTO DATA(message).
out->plain->write( message->value-message->get_text( ) ).
out->plain->write( message->value-level_of_detail->value ).
out->plain->write( message->value-timestamp->value ).
ENDLOOP.
Im Ergebnis geben wir die verschiedenen Informationen in die Konsole von Eclipse aus.
Suche
Haben wir für unseren Prozess kein entsprechendes Handle gespeichert, sondern haben nur einige Informationen, wie eine Abgrenzung nach Externer ID oder Zeit, dann müssen wir die bestehenden Logs durchsuchen.
Filter
Dazu definieren wir uns im ersten Schritt ein Filterkriterium, über das wir die Einträge einschränken wollen. Dazu findest du das Attribut LOG_FILTER an der Klasse XCO_CP_BAL. Dort stehen uns verschiedene Attribute zur Verfügung, über die wir die Einschränkung machen können.
In diesem Beispiel filtern wir über die Externe ID, da wir zuvor verschiedene Logs mit verschiedenen Referenzen erzeugt haben. Der Methode übergeben wir einen Constraint für die Abfrage.
DATA(filter_external_id) = xco_cp_bal=>log_filter->external_id(
xco_cp_abap_sql=>constraint->contains_pattern( '*02*' ) ).
Über die Klasse XCO_CP_ABAP_SQL kannst du so einen Constraint erzeugen und auch befüllen. Hier stehen die gleichen Abfragen wie bei einer Range zur Verfügung. Daher verwenden wir die Methode CONTAINS_PATTERN (CP), um nach einem Pattern zu suchen. Aber Vorsicht, anders als in der Dokumentation beschrieben, haben wir nur mit Stern (*) ein Ergebnis bekommen.
Abfrage
Sind unsere Filter definiert, dann können wir wieder die Persistenz aufrufen. Da wir von der Datenbank lesen wollen verwenden wir DATABASE und gehen in diesem Fall über das LOGS Attribut. Der WHERE Methode können wir nun alle unsere Filter übergeben und rufen zum Abschluss die GET Methode auf.
DATA(found_logs) = xco_cp_bal=>for->database( )->logs->where( VALUE #( ( filter_external_id ) ) )->get( ).
Verarbeitung
Die Selektion der Logs kann etwas dauern, je nach Abfrage der Daten. Am Ende erhalten wir eine Tabelle mit Log Instanzen, die wir dann entsprechend verarbeiten und auswerten können. In diesem Fall lassen wir uns den Handle und die Externe ID zur Analyse geben.
LOOP AT found_logs INTO DATA(log).
out->write( log->handle ).
out->write( log->header->get_external_id( ) ).
ENDLOOP.
Wir haben nach allen Objekten mit "02" im Namen der Externen ID gesucht und so sieht nun unser entsprechendes Ergebnis aus. Ausgabe des Handles und der Externen ID:
Vergleich
In diesem Abschnitt vergleichen wir die verschiedenen Klassen einmal direkt miteinander und schauen uns dabei den allgemeinen Support, sowie die spezifischen Meldungen an. Grundsätzlich basieren alle Klassen auf dem Framework der BAL_LOG* Funktionsbausteine, wenn es um das Handling der Meldungen geht.
| BAL_LOG_CREATE | CL_BALI_LOG | XCO_CP_BAL | AML | |
|---|---|---|---|---|
| Allgemein | ||||
| Sprachversion | Classic | ABAP Cloud | ABAP Cloud | ABAP Cloud |
| Pflege | SLG0 | ADT | ADT | ADT |
| ABAP OO | ✔️ | ✔️ | ✔️ | |
| Testbar | ✔️ | |||
| Verfallsdatum | ✔️ | ✔️ | ✔️ | |
| Fehlerfall | ✔️ | ✔️ | ||
| Nachrichten (nativ) | ||||
| T100 | ✔️ | ✔️ | ✔️ | ✔️ |
| System | ✔️ | ✔️ | ✔️ | |
| Ausnahme | ✔️ | ✔️ | ✔️ | ✔️ |
| Text/String | ✔️ | ✔️ | ✔️ | ✔️ |
| BAPI | ✔️ | ✔️ | ||
| XCO_MESSAGE | ✔️ | ✔️ | ||
Die folgenden Kritierien haben wir dabei verglichen:
- Pflege - Wo wir das Application Log Objekt erzeugt und gewartet.
- Testbar - Ist die Klasse testbar geschrieben, sodass sie ohne viel Aufwand zur Laufzeit gemockt werden kann.
- Verfallsdatum - Kann das Löschdatum gesetzt werden, sodass nach x Tagen das Log vom System gelöscht wird.
- Fehlerfall - Im Falle eines Abbruchs (Dump), werden die Meldungen trotzdem persistiert.
- Nachrichten - Hier geht es um die native Bereitstellung einer Methode oder Möglichkeit, die Meldung ins Log zu übernehmen. Meist ohne den Aufwand eines Mappings.
In diesem Artikel hatten wir die XCO Klassen thematisiert, weitere Informationen zur allgemeinen ABAP Cloud API findest du in diesem Artikel. Möchtest du mehr zum Open Source Projekt ABAP Message Logger erfahren, dann haben wir auch einen eigenen Artikel dafür. Der Logger wurde mit der Intention geschrieben, möglichst viele der Punkte von oben abzudecken, einfach und testbar implementierbar zu bleiben.
Vollständiges Beispiel
Das vollständige Beispiel der beiden Klasse findest du bei uns im GitHub Repository. In diesem Commit findest du die Änderungen aus dem heutigen Artikel und kannst die Schritte bei dir im System nachvollziehen.
Fazit
Neben der neuen Standard API für ABAP Cloud gibt es nun auch eine zweite Variante aus dem Bereich der XCO Bibliothek. Grundsätzlich liegt der Fokus der Logging Klasse auf dem XCO Ökosystem, mit den Interfaces und Verhalten. Schaust du dir den Umfang des Frameworks an, gibt es sicherlich noch Verbesserungspotential.
Weitere Informationen:
SAP Help - Business Application Log





