APM-Spans als JFR-Ereignisse aufzeichnen

APM-Tracer und APM-Agent unterstützen die Aufzeichnung von APM-Spans als JFR-Ereignisse.

Aktuell wird JDK 11 oder höher unterstützt.

Informationen zum Aufzeichnen von APM-Spans als JFR-Ereignisse bei Verwendung des APM-Agents finden Sie unter APM-Spans als JFR-Ereignisse aufzeichnen unter APM-Java-Agents auf Anwendungsservern durch Provisioning und Deployment bereitstellen.

Hinweis

Java Flight Recorder (JFR) ist ein Tool zum Erfassen von Diagnose- und Profilingdaten über eine ausgeführte Java-Anwendung. Informationen zu Java Flight Recorder (JFR) und Java Mission Control (JMC) finden Sie unter JDK Mission Control.

APM-Ereignisse in JFR-Aufzeichnungen erfassen

So erfassen Sie APM-Ereignisse in JFR-Aufzeichnungen bei Verwendung des APM-Tracers:

  1. Stellen Sie sicher, dass der APM-Tracer ordnungsgemäß arbeitet.

    Öffnen Sie den Trace-Explorer, und vergewissern Sie sich, dass Sie alle Traces anzeigen können. Informationen zum Öffnen und Verwenden des Trace-Explorers finden Sie unter Traces im Trace-Explorer überwachen.

  2. Fügen Sie dem Maven-Projekt eine Abhängigkeit hinzu, mit der der APM-Tracer Ereignisse in die JFR-Aufzeichnungen der Helidon-JVM einfügen kann.

    <dependency>
        <groupId>com.oracle.apm.agent.java</groupId>
        <artifactId>apm-java-agent-jfr11</artifactId>
        <version>[1.0.1389,)</version>
    </dependency>
  3. Starten Sie eine Aufzeichnung.

    Um zu testen, ob alles ordnungsgemäß funktioniert, müssen Sie anhand Ihrer bevorzugten Methode eine Aufzeichnung starten (entweder über die JDK Mission Control-UI oder das JCMD-Befehlszeilenutility). Nachdem eine Aufzeichnung gestartet wurde, werden Traceereignisse auf der JDK Mission Control-UI angezeigt, wenn die Aufzeichnung angezeigt wird.

    Um zu überprüfen, ob APM-Traceereignisse ordnungsgemäß zu JFR-Aufzeichnungen hinzugefügt wurden, melden Sie sich bei JDK Mission Control an, und vergewissern Sie sich, dass die APM-Traces im Ereignisbrowser sichtbar sind: Klicken Sie auf APM OpenTracing, und vergewissern Sie sich, dass APM-Traceereignisse sichtbar sind.

JFR-Ereignisse im APM-Tracer konfigurieren

(Optional) Dieser Schritt ist optional, wenn Sie das Reporting der Ereignisse anpassen möchten.

Um die Analyse der JFR-Aufzeichnungsereignisse zu vereinfachen, ist jedes Ereignis in einer Kategorie oder einem Ereignistyp organisiert.

Standardkategorie

Im APM-Tracer wird die Standardkategorie für APM-JFR-Ereignisse anhand des Inhalts von Span Operation Name (im Feld name im Span) ermittelt. Das Tag component kann nicht aufgefüllt werden und daher nicht als Standardkategorie verwendet werden.

Ereignisse

Mit einem Ereignistyp können die Ereignisse organisiert und auf der JMC-Benutzeroberfläche klassifiziert werden. Wenn der APM-Tracer einen Span abruft, kann er ein Ereignis für diesen Span generieren, muss jedoch den Ereignistyp dieses spezifischen Ereignisses ermitteln.

Beispiele für Ereignistypen sind servlet, jdbc und jax-rs.

Ereignistypkonfiguration

Die Konfiguration eines Ereignistyps oder einer Ereigniskategorie kann auf verschiedene Weise durchgeführt werden. Nachfolgend sind die verschiedenen Anwendungsfälle aufgeführt:

  • Fall 1: component-Tag

    Dies ist die einfachste Methode zur Klassifizierung eines Ereignisses. Dies ist die empfohlene Methode.

    In den meisten Szenarios enthält der OpenTracing-Span das Tag component. Der Wert des Tags component wird zur Ermittlung des Ereignistyps herangezogen.

    Beispiel:

    {  "id":"e926ff3d06013045",
      "trace-id":"49abd92e69786853e926ff3d06013045",
      "parent-id":"6ef54ec2c524c99a",
      "name":"content-write",
      "ts-micros":1614190751360177,
      "td-micros":219348,
      "attributes":{
        "server":"Helidon SE",
        "http.url":"http://localhost:8079/health",
        "http.status_code":200,
        "component":"helidon-webserver",
        "http.method":"GET",
        "organization":"development"
      },
      "events":[
      ]
    },

    In diesem Fall wird dem generierten Ereignis der Ereignistyp helidon-webserver zugewiesen, da dies der Wert des Tags component ist.

  • Fall 2: Anderes Tag

    Wenn die Anwendung nicht das Tag component, aber ein anderes Tag verwendet oder die Tags von einer Library generiert werden, kann der APM-Tracer so konfiguriert werden, dass der Ereignistyp aus diesem anderen Tag gelesen wird.

    Beispiel: Beim folgenden Span kann der Ereignistyp aus dem Tag span.type gelesen werden:

    {  "id":"e926ff3d06013045",
      "trace-id":"49abd92e69786853e926ff3d06013045",
      "parent-id":"6ef54ec2c524c99a",
      "name":"content-write",
      "ts-micros":1614190751360177,
      "td-micros":219348,
      "attributes":{
        "server":"Helidon SE",
        "http.url":"http://localhost:8079/health",
        "http.status_code":200,
        "span.type":"helidon-webserver",
        "http.method":"GET",
        "organization":"development"
      },
      "events":[
      ]
    },

    In diesem Fall kann der APM-Tracer den Ereignistyp aus dem Tag span.type lesen, indem Sie beim Starten der Java-Anwendung die folgende Systemeigenschaft verwenden:

    java -Dcom.oracle.apm.agent.jfr.category.tag=span.type ...
  • Fall 3: Vorgangsname verwenden, wenn keine Tags verfügbar sind

    Wenn die Anwendung keine Tags mit nützlichen Kategorien verwendet, können Sie den Ereignistyp anhand von Operation Name ermitteln. Diese Methode wird jedoch nicht empfohlen.

    Das JFR-System erfordert, dass der Name des Ereignistyps eine gültige Java-ID ist. Operation Name enthält jedoch häufig Leerzeichen und auch andere unzulässige Zeichen. Der APM-Tracer konvertiert Operation Name in eine gültige ID, indem alle unzulässigen Zeichen durch Unterstriche ersetzt werden.

    java -Dcom.oracle.apm.agent.jfr.category.default=ORACLE_APM_USE_SPAN_OPERATION_NAMES
    Hinweis

    Operation Name wird nur verwendet, wenn das Kategorietag fehlt oder leer ist.

    Dies ist keine einfache Lösung, weil Operation Name eindeutige Token wie IDs enthalten kann, durch die jedes Ereignis einen eigenen Ereignistyp erhält. Darüber hinaus führt die Konvertierung von Operation Name in eine gültige ID zu weiteren Problemen bei der Konfiguration des Ereignistyps, um festzulegen, welche Felder im Ereignis benötigt werden. Außerdem muss die Konfiguration anhand des konvertierten Operation Name erfolgen, da andernfalls viele verschiedene Varianten von Operation Name auf dieselbe Weise konfiguriert werden müssten.

  • Fall 4: Es sind keine Tags verfügbar, und alle Vorgangsnamen sind eindeutig.

    In diesem Fall sind keine Informationen zur Klassifizierung der Ereignistypen verfügbar. Dies ist das Worst-Case-Szenario, bei dem alle Ereignisse den gleichen Ereignistyp erhalten. Dagegen erhalten alle Ereignisse einen eindeutigen Ereignistyp, wenn sie wie in Fall 3 oben beschrieben konfiguriert werden. Die einzige Möglichkeit dazu besteht darin, den Namen dieses Standardereignistyps auszuwählen. Dies kann wie nachfolgend beschrieben konfiguriert werden.

    java -Dcom.oracle.apm.agent.jfr.category.default=Unknown
    Hinweis

    Der Standardwert wird nur verwendet, wenn das Kategorietag fehlt oder leer ist.

    In diesem Fall erhalten alle Ereignisse den Ereignistyp Unknown oder einen beliebigen benutzerdefinierten Wert.

Felder für den Ereignistyp

Für jeden Ereignistyp kann mindestens ein Feld mit spezifischen Daten für dieses Ereignis hinzugefügt werden.

Die Liste der Felder, die dem Ereignistyp hinzugefügt werden können, muss in der ACML-Datei konfiguriert werden. Erst dann können die Felder in JFR veröffentlicht werden. Für jedes Feld sind folgende Informationen erforderlich:
  • Name.
  • Typ (Ganzzahl, Float, Zeichenfolge, Thread).
  • Label.
  • Beschreibung.
Als Beispiel dient die folgende Felddefinition für traceID:
- name: traceID
  type: String
  label: New Trace ID
  description: New Opentracing Trace ID

ACML-Datei erstellen

Dies ist ein optionaler Schritt. Wenn die Standardeinstellungen wie erwartet funktionieren, können Sie diesen Schritt überspringen.

Sie können eine ACML-Datei erstellen, wenn Sie die Standardeinstellungen ändern und die Aufzeichnungen anpassen möchten.

Das folgende Beispiel zeigt das Format einer ACML-Datei zur Konfiguration des Ereignisloggings in JFR, indem die integrierten Standardeinstellungen für den Helidon-Microservices-Container überschrieben werden:

caseSensitiveFieldName: false
recordCallStack: true

eventTypes:
  helidon-webserver:
    name: helidon-webserver
    label: Helidon Webserver Events
    description: All events based on helidon webserver
    recordCallStack: true
    # All fields must be provided here.
    # Fields are NOT incremental since that would make them impossible to remove 
    fields:
      - name: traceID
        type: String
        label: New Trace ID
        description: New Opentracing Trace ID
      - name: spanID
        type: String
        label: New Span ID
        description: New Opentracing Span ID
      - name: http.url
        type: String
        label: New HTTP URL
        description: The New URL for the HTTP endpoint being hit
      - name: organization
        type: String
        label: Organization
        description: The New Organization value of this call
      - name: startThread
        type: Thread
        label: Start Thread
        description: The thread on which this event started
      - name: http.status_code
        type: int
        label: Status Code
        description: The HTTP Response status code
      - name: http.method
        type: String
        label: HTTP Method
        description: The HTTP Method

Sie können das obige Format der ACML-Datei bei Verwendung von APM-Agent und APM-Tracer verwenden. Beim APM-Tracer funktioniert es für alle Container wie Helidon, Springboot und Micronaut.

Häufig gestellte Fragen

  1. Welche Einstellung hat Priorität, wenn die Eigenschaften com.oracle.apm.agent.jfr.category.tag und com.oracle.apm.agent.jfr.category.default zusammen angegeben sind?

    Wenn beide einen Wert erhalten, wird zuerst im Span nach dem Kategorietag gesucht. Wenn es gefunden wird, wird es verwendet. Wenn es fehlt, wird der Standardwert verwendet.

  2. Ist für den APM-Tracer eine Konfigurationsdatei erforderlich? Kann ich die Eigenschaften auch ohne Datei angeben?

    Eine Konfigurationsdatei ist nicht erforderlich. Wenn die Standardeinstellung für Sie funktioniert, benötigen Sie keine Konfigurationsdatei und können dennoch die Eigenschaften angeben.

  3. Warum sind in einigen Fällen Einträge scheinbar dupliziert? Beispiel: Das folgende Snippet aus der ACML-Konfigurationsdatei enthält den Eintrag helidon-webserver zweimal:
    eventTypes:
      helidon-webserver:
        name: helidon-webserver

    Der erste Eintrag von helidon-webserver wird aus den Tags oder dem Vorgangsnamen gelesen. Wenn der Ereignistyp wie im obigen Beispiel klar, leicht lesbar und intuitiv ist, können Sie denselben Ereignistyp an die JFR-Aufzeichnung senden, sodass er auch in JMC angezeigt wird.

    Bei Verwendung von operation name kann jedoch in bestimmten Fällen ein Ereignistyp wie q_AxPsCbac9Ykp0HjpU+ENCiYHKl5HzMCmR02AfGzow3A= generiert werden. Hierbei handelt es sich um eine JDBC-Abfrage von einem DB-Client. In diesem Fall sollte der an die JFR-Aufzeichnung gesendete Name in einen intuitiven Namen geändert werden. Hierzu kann das folgende Beispiel verwendet werden:
    eventTypes:
      q_AxPsCbac9Ykp0HjpU+ENCiYHKl5HzMCmR02AfGzow3A=:
        name: jdbc-select-query
  4. Warum muss recordCallStack auch auf der obersten Ebene vorhanden sein, wenn recordCallStack für jeden Ereignistyp angegeben werden kann?

    Für maximale Flexibilität bei der Aufzeichnung des Aufrufstacks werden zwei Anwendungsfälle unterstützt. Die Aufzeichnung des Aufrufstacks kann global deaktiviert und für bestimmte Ereignistypen selektiv aktiviert werden. Ebenso kann sie global aktiviert und für bestimmte Ereignistypen selektiv deaktiviert werden. Beide Anwendungsfälle werden unterstützt, sodass die Einstellung sowohl auf der obersten Ebene als auch auf der Ereignisebene möglich ist.

  5. Einige Spans wurden nicht konfiguriert und werden ignoriert. Können diese Ereignisse auch ohne Konfiguration erfasst werden?

    Ja. Wenn Sie in der Hauptkonfiguration auf der obersten Ebene allowUnconfiguredEvents: true festlegen, werden diese Ereignisse erfasst. In diesem Fall kann nicht ermittelt werden, welche Felder erfasst werden sollen. Nur die folgenden Standardfelder werden erfasst: traceID, spanID, parentSpanID, startThread und operationName.

  6. Wenn ich com.oracle.apm.agent.jfr.category.default=ORACLE_APM_USE_SPAN_OPERATION_NAMES für durch den Vorgangsnamen definierte Kategorien verwende, muss der Vorgangsname genau mit dem Ereignistypnamen in der Konfigurationsdatei übereinstimmen? Falls ja, muss ich für jeden Vorgang einen Ereignistyp angeben, wenn die Vorgangsnamen eindeutig sind?

    Ja, der Name muss mit dem Ereignistypnamen in der Konfigurationsdatei übereinstimmen. Auch wenn viele eindeutige Vorgangsnamen vorhanden sind, müssen Sie für jeden Vorgang einen Ereignistyp angeben, da für jeden dieser Ereignistypen wahrscheinlich unterschiedliche Felder konfiguriert werden müssen.

  7. Ich kann den Ereignistyp nicht konfigurieren, weil der Vorgangsname in eine Java-ID konvertiert wird. Wie kann ich bestimmen, in welche ID der Vorgangsname konvertiert wird?

    Alle unzulässigen Zeichen werden durch Unterstriche ersetzt. Wenn Sie einen Java-Beispielcode benötigen, um Ihre Zeichenfolgen in IDs zu konvertieren, können Sie den folgenden Code verwenden. Dieser nutzt dieselbe Routine, mit der APM die Zeichenfolgen konvertiert.
    // Convert an arbitrary string into a valid java identifier by replacing non-identifier chars with an underscore
    public static String getJavaIdentifier(String inString)
    {
        if (inString == null || inString.length() == 0)
           return inString;
        StringBuilder stringBuilder = new StringBuilder();
        char[] allChars = inString.toCharArray();
    
        if(Character.isJavaIdentifierStart(allChars[0]))
            stringBuilder.append(allChars[0]);
        else
            stringBuilder.append("_");
    
        for (int i = 1; i < allChars.length; i++)
        {
            if (Character.isJavaIdentifierPart(allChars[i]))
                stringBuilder.append(allChars[i]);
            else
                stringBuilder.append("_");
        }
        return stringBuilder.toString();
    }
  8. Ist der Namensabgleich mit einem regulären Ausdruck möglich?

    Nein, reguläre Ausdrücke werden nicht unterstützt.