This is a test message to test the length of the message box.
Login
ABAP Cloud Message Logging
Erstellt von Software-Heroes

ABAP Cloud - Message Logging

36

Wie loggst du im Moment eigentlich Nachrichten über größere Blöcke von ABAP Code und wie gehst du dabei mit den unterschiedlichen Formaten um? Mal wieder ein neues Open Source Projekt.

Werbung


In diesem Artikel schauen wir uns ein neues Open Source Projekt von uns im Bereich ABAP Cloud an. Dabei gehen wir auf die Nutzung und den Aufbau des Frameworks ein und wie du es effektiv nutzen kannst.

 

Einleitung

Just another ABAP Logger ... for ABAP Cloud. BAPIs erzeugen meist über ihre RETURN Parameter Nachrichten, neuere Implementierung werfen eine Ausnahme, Meldungen befinden sich in Systemfeldern. Die Anzahl der Informationen, die es zu Loggen gibt, kann vielfältig sein. Dann kommt vielleicht noch das Thema Übersetzung dazu, wenn Meldungen im Application Log gesichert werden und später in einer anderen Sprache geprüft werden. In solchen Fällen sollten nicht nur einfache Texte und Strings gesichert werden. Hier kommt der ABAP Message Logger, kurz AML, zum Einsatz, der die Aufgaben für dich übernehmen kann.

 

Architektur

Schauen wir uns die Architektur der Komponente an und was die eigentliche Idee dahinter ist. Normalerweise fokussieren viele Entwicklungen auf das Speichern der Meldungen und Fehler im Application Log, in den meisten Fällen wird das aber gar nicht benötigt und ist eher eine Funktion des Loggers. Bei der Umsetzung haben wir daher auf die folgenden Punkte geachtet:

  • Testbar und Mockbar - Nutzbar in ABAP Unit Tests und für alle Arten von Entwicklungen, wo du testbar bleiben möchtest (Factory und Injector).
  • Konfiguration - Die Konfiguration musst du nur einmal bei Erzeugung des Objekts machen und dir dann bei der Verarbeitung keine Gedanken mehr machen.
  • Erzeugung - Für die Erzeugung bieten wir eine Factory, die neue Instanzen generiert oder ein Singleton mit Buffer, zur Erzeugung und Bereitstellung verschiedener Objekte.
  • ABAP Cloud - Das neue Application Log, Application Jobs und das Speichern über eine zweite Datenbankverbindung werden für den ABAP Cloud Entwickler unterstützt.
  • RAP - Nachrichten sammeln und gebündelt an das RAP Framework zurückgeben ist auch kein Problem.
  • Exceptions - Die Behandlung von Fehlern und Meldung erfolgt still und mit wenig Aufwand durch das Framework, dein Quellcode bleibt leicht und sauber.
  • Kontext - Zusätzliche Daten im Kontext sichern? Ist aktuell noch in Planung für die Umsetzung.

 

Verwendung

In diesem Kapitel schauen wir uns einmal die Verwendung und die effektive Nutzung des Frameworks an.

 

Erstellung

Für die Erstellung stehen dir zwei Methoden der Factory ZCL_AML_LOG_FACTORY zur Verfügung, die du verwenden kannst:

  • CREATE - Übernimmt die Einstellungen und erzeugt dir ein neues Log Objekt, dass du direkt für die Nutzung erhältst.
  • GET_INSTANCE - Die Methode gibt dir die gewünschte Instanz zu einem Log Objekt zurück. Dabei wir die Identifikation verwendet die Instanz zu finden. Die Einstellungen müssen nur zur Erstellung übergeben werden.

 

Schauen wir uns dazu ein sehr einfaches Beispiel an wie du minimal ein Log Objekt erzeugen kannst. Dabei übergeben wir keinerlei Informationen und lassen und ein leeres Objekt zurückgeben.

DATA(new_log) = zcl_aml_log_factory=>create( ).

 

In einem zweiten Beispiel erzeugen wir uns eine Instanz und übergeben einiges Einstellungen. Dabei legen wir eine Standard Nachrichtenklasse fest, setzen die Standard Typen auf S (Success) und schalten die Stacked-Exceptions aus. Mehr zu den verschiedenen Einstellungen findest du im Git Repository.

log_setting = zcl_aml_log_factory=>create( VALUE #( default_message_class = 'Z_AML'
                                                    default_message_type  = 'S'
                                                    no_stacked_exception  = abap_true ) ).

 

Als dritte Möglichkeit erzeugen wir uns ein Log über die Methode GET_INSTANCE. Dabei erhalten wir nicht nur ein Objekt, sondern auch einen Eintrag im Puffer. Daher legen wir das Log nicht als Attribut in der ausführbaren Klasse ab. Grundsätzlich kannst du hier ebenso die Einstellungen übergeben.

log_specific = zcl_aml_log_factory=>get_instance( identification = 'SPECIFIC_INSTANCE' ).

 

Logging

Kommen wir nun zum eigentlichen Punkt, das Logging. Wie bekommen wir die verschiedenen Meldungen in das Objekt und wie werden diese eigentlich gesichert? Wenn du Meldungen hinzufügen möchtest, dann stehen wir zahlreiche ADD_MESSAGE* Methoden zur Verfügung. Es sollten so weit die gängigen Methoden und Typen vertreten sein, sodass eine Konvertierung außerhalb der Klasse nicht nötig ist. Dazu ein Beispiel, um eine einfache Meldung zu übernehmen.

log_default->add_message( class  = 'Z_AML'
                          type   = 'S'
                          number = '001'
                          v1     = 'Placeholder' ).

 

Im nächsten Beispiel erzeugen wir eine Ausnahme, fangen sie ab un übergeben sie an das Logging Objekt. Hierbei handelt es sich um eine einfache Ausnahme. Grundsätzlich werden Ausnahmen, die über PREVIOUS aufgebaut werden im Anschluss ausgepackt und alle Meldungen übernommen. 

TRY.
    RAISE EXCEPTION NEW cx_sy_itab_line_not_found( ).
    
  CATCH cx_root INTO DATA(error).
    log_setting->add_message_exception( error ).
ENDTRY.

 

In diesem Beispiel erzeugen wir eine Meldung über eine Standard MESSAGE Anweisung und befüllen damit die Systemfelder (SY). Für die Übergabe müssen wir nur die Methode aufrufen und die Systemfelder werden über die XCO Klasse ausgelesen.

MESSAGE e002(z_aml) WITH 'Dummy' INTO DATA(dummy_message).
log_specific->add_message_system( ).

 

Hinweis: Grundsätzlich haben wir uns beim Design an die beiden Methoden von Clean ABAP gehalten: "Keep methods small" und "Do one thing, do it well, do it only". Damit gibt es mehr als eine Methode, für den jeweils richtigen Typen.

 

Hilfsmethoden

Im nächsten Schritt wollen wir das eigentliche Log prüfen. Damit wir uns nicht jede Meldung anschauen müssen, gibt es verschiedene Hilfsmethoden, über die wir an weitere Informationen im Objekt kommen. Möchtest du zum Beispiel wissen, ob es Meldungen im Log gibt, kannst du dir Method verwenden, um an die Anzahl zu kommen.

log_specific->get_number_of_messages( )

 

Wollen wir prüfen, ob es Fehler im Log gibt, dann können wir das über die Methode HAS_ERROR machen. Mit der ähnlichen Methode HAS_WARNING, können wir prüfen, ob mindestens Warnungen enthalten sind, wenn diese für dich bereits Fehler sind.

IF log_default->has_error( ).
  out->write( `There are some errors` ).
ELSE.
  out->write( `No errors found` ).
ENDIF.

 

Haben wir mehrere Logs, können wir diese mit wenig Aufwand auch zusammenbringen. Über die Methode MERGE_LOG, übernehmen wir alle Meldungen des übergebenen Logs. Einstellungen werden dabei aber nicht übernommen, sondern nur die gepufferten Meldungen. Die Methode bietet sich immer dann an, wenn du aus anderen Verarbeitungen Logs erhältst.

log_setting->merge_log( log_default ).

 

Zum Abschluss können wir auch nach Meldungen im Log suchen. Dazu kannst du nach verschiedenen Elementen wie die Nachrichtenklasse oder die Nachrichtennummer suchen. Als Ergebnis erhältst du eine Struktur mit dem Status und der ersten Meldung die gefunden wurde, falls du zum Beispiel an die Platzhalter möchtest.

IF log_setting->search_message( VALUE #( msgid = 'Z_AML' msgno = '001' ) )-found = abap_true.
  out->write( `Found the specific message in the log.` ).
ENDIF.

 

Verarbeitung

Nachdem wir nun das Log erzeugt, mit Meldungen befüllt und einige Informationen validiert haben, kommen wir nun zur eigentlichen Verarbeitung. Was können wir nun mit den Meldungen machen:

  • Status - Uns war nur der Status der Verarbeitung wichtig, dann können wir das einfach über die Hilfsmethoden machen.
  • Meldungen - Wir sind an den Meldungen und Inhalten interessiert, dann gibt es zahlreiche Methoden vom Typen GET_MESSAGES* über die wir die Inhalte in den passenden Formaten konsumieren können.
  • Speichern - Möchtest du alle Meldungen im Application Log sichern, dann kannst du dies machen. Über Einstellungen auch am Application Job oder über eine zweite Datenbankverbindung.

 

Schauen wir uns dazu einmal ein paar Beispielmethoden an. Möchten wir zum Beispiel die Meldungen als BAPI zurückbekommen, dann kannst du dazu die passende Methode aufrufen.

DATA(log_specific) = zcl_aml_log_factory=>get_instance( identification = instance_identification ).
out->write( log_specific->get_messages_bapi( ) ).

 

Möchtest du das Application Log speichern, dann steht dir die SAVE Methode zur Verfügung. Hier müssen die Einstellungen zu Beginn über den Settings Parameter gesetzt werden. Die SAVE Methode gibt ein Ergebnis zurück, dort findest du, ob die Meldungen gespeichert wurden, das Log Handle und mögliche Fehlermeldungen, wenn es Probleme gab.

DATA(result) = log_default->save( ).
out->write( result ).

 

Für das ABAP RESTful Application Programming Model (RAP) gibt es eine spezifische Methode, die eine Tabelle von RAP Exceptions mit dem Interface IF_ABAP_BEHV_MESSAGE zurückgibt. Damit kannst du Exceptions zum Beispiel auch direkt über Others and das UI weitergeben. Dazu der Ausschnitt aus einer Action in RAP, dort findest du normalerweise den REPORTED Parameter mit dem Feld %OTHER. Wenn du diesen mit den Meldungen befüllst, dann werden diese an das UI zurückgegeben und als Message Box angezeigt, wenn du mehr als eine Meldung zurückgibst.

reported-%other = log_default->get_messages_rap( ).

 

Vollständiges Beispiel

Das Projekt findest du bei uns im GitHub Repository. Wenn du dich beteiligen willst oder Verbesserungsvorschläge hast, dann gern einen Issue öffnen. Wenn du noch Fragen zum Projekt hast, gern auch hier über die Webseite stellen. Das Projekt ist komplett Open Source und kann frei von dir verwendet werden.

Hier findest du noch die Testklasse, wenn du die verschiedenen Methoden einmal nachstellen möchtest.

CLASS zcl_bs_demo_aml_logging DEFINITION
  PUBLIC FINAL
  CREATE PUBLIC.

  PUBLIC SECTION.
    INTERFACES if_oo_adt_classrun.

  PRIVATE SECTION.
    CONSTANTS instance_identification TYPE zcl_aml_log_factory=>identification VALUE 'SPECIFIC_INSTANCE'.

    DATA log_default TYPE REF TO zif_aml_log.
    DATA log_setting TYPE REF TO zif_aml_log.

    METHODS create_log_object.
    METHODS create_messages.

    METHODS check_content
      IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.

    METHODS work_with_content
      IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.
ENDCLASS.


CLASS zcl_bs_demo_aml_logging IMPLEMENTATION.
  METHOD if_oo_adt_classrun~main.
    create_log_object( ).
    create_messages( ).
    check_content( out ).
    work_with_content( out ).
  ENDMETHOD.


  METHOD create_log_object.
    log_default = zcl_aml_log_factory=>create( ).

    log_setting = zcl_aml_log_factory=>create( VALUE #( default_message_class = 'Z_AML'
                                                        default_message_type  = 'S'
                                                        no_stacked_exception  = abap_true ) ).

    DATA(log_specific) = zcl_aml_log_factory=>get_instance( identification = instance_identification ).
    log_specific->add_message_text( |This is a specific log: { instance_identification }| ).
  ENDMETHOD.


  METHOD create_messages.
    log_default->add_message( class  = 'Z_AML'
                              type   = 'S'
                              number = '001'
                              v1     = 'Placeholder' ).

    TRY.
        RAISE EXCEPTION NEW cx_sy_itab_line_not_found( ).

      CATCH cx_root INTO DATA(error).
        log_setting->add_message_exception( error ).
    ENDTRY.

    DATA(log_specific) = zcl_aml_log_factory=>get_instance( identification = instance_identification ).

    MESSAGE e002(z_aml) WITH 'Dummy' INTO DATA(dummy_message) ##NEEDED.
    log_specific->add_message_system( ).
  ENDMETHOD.


  METHOD check_content.
    DATA(log_specific) = zcl_aml_log_factory=>get_instance( identification = instance_identification ).
    out->write( log_specific->get_number_of_messages( ) ).

    IF log_default->has_error( ).
      out->write( `There are some errors` ).
    ELSE.
      out->write( `No errors found` ).
    ENDIF.

    log_setting->merge_log( log_default ).

    IF log_setting->search_message( VALUE #( msgid = 'Z_AML'
                                             msgno = '001' ) )-found = abap_true.
      out->write( `Found the specific message in the log.` ).
    ENDIF.
  ENDMETHOD.


  METHOD work_with_content.
    out->write( log_setting->get_messages_flat( ) ).

    DATA(log_specific) = zcl_aml_log_factory=>get_instance( identification = instance_identification ).
    out->write( log_specific->get_messages_bapi( ) ).

    DATA(result) = log_default->save( ).
    out->write( result ).
  ENDMETHOD.
ENDCLASS.

 

Fazit

Das Handling von Nachrichten und Fehlern im ABAP Code ist immer eine persönliche Sache und viele Entwickler haben hier ihre eigene Logik. Die schlechteste Entscheidung ist allerdings immer noch eine eigene Logik pro Entwicklung.


Enthaltene Themen:
ABAP CloudABAPLoggingOpen Source
Kommentare (0)



Und weiter ...

Bist du zufrieden mit dem Inhalt des Artikels? Wir posten jeden Dienstag und Freitag neuen Content im Bereich ABAP und unregelmäßig in allen anderen Bereichen. Schaue bei unseren Tools und Apps vorbei, diese stellen wir kostenlos zur Verfügung.


ABAP Cloud - Clean Core Level Concept

Kategorie - ABAP

Das neue Clean Core Level Concept für ABAP Cloud ist da, dieses löst das 3-TIER Model ab. In diesem Artikel schauen wir uns die Änderungen und Anpassungen im Detail an.

15.08.2025

ABAP Cloud - Test Daten Container

Kategorie - ABAP

Test Daten Container sind unter ABAP Cloud nicht freigegeben, wie also auf generische Testdaten zugreifen können? Hier ein Vorschlag für ein einfaches Framework.

08.07.2025

ABAP Cloud ... ohne BTP?

Kategorie - ABAP

In diesem Artikel gehen wir der Frage nach, ob ABAP Cloud auch ohne BTP möglich ist und was du dabei beachten solltest.

24.06.2025

ABAP Cloud - Fähigkeiten für den Start

Kategorie - ABAP

Wann kannst du eigentlich mit moderner ABAP Entwicklung starten und welche Fähigkeiten brauchst du dafür mindestens? Lass uns diese Frage gemeinsam klären.

17.06.2025

ABAP Cloud - Systemfelder (Lösung)

Kategorie - ABAP

Wie könnte eine Lösung für ABAP Cloud aussehen, um an die Systeminformationen und -felder zu gelangen und dabei testbar und offen zu bleiben? Hier mehr.

13.06.2025