JFRイベントとしてのAPMスパンの記録

APMトレーサおよびAPMエージェントでは、JFRイベントとしてのAPMスパンの記録をサポートしています。

現在、JDK 11以上がサポートされています。

この項はAPMトレーサに適用され、内容は次のとおりです:

APMエージェント使用時におけるJFRイベントとしてのAPMスパンの記録の詳細は、アプリケーション・サーバーでのAPM JavaエージェントのプロビジョニングおよびデプロイJFRイベントとしてのAPMスパンの記録を参照してください。

ノート

Java Flight Recorder (JFR)は、Javaアプリケーションの実行に関する診断データおよびプロファイリング・データを収集するためのツールです。Java Flight Recorder (JFR)およびJava Mission Control (JMC)の詳細は、JDK Mission Controlを参照してください。

JFR記録でのAPMイベントの取得

APMトレーサの使用時にJFR記録でAPMイベントを取得するには、次のステップを実行します:

  1. APMトレーサが正しく動作していることを確認します。

    トレース・エクスプローラを開き、すべてのトレースが表示されることを確認します。トレース・エクスプローラのオープンおよび使用の詳細は、トレース・エクスプローラでのトレースのモニターを参照してください。

  2. Helidon JVMによって行われたJFR記録にAPMトレーサがイベントを追加できるように、Mavenプロジェクトに依存関係を追加します。

    <dependency>
        <groupId>com.oracle.apm.agent.java</groupId>
        <artifactId>apm-java-agent-jfr11</artifactId>
        <version>[1.0.1389,)</version>
    </dependency>
  3. 記録を開始します。

    すべてが正しく機能していることをテストするには、希望の方法を使用して記録を開始する必要があります(JDK Mission Control UIまたはJCMDコマンドライン・ユーティリティを使用できます)。記録が開始された後は、記録を表示するとJDK Mission Control UIにトレース・イベントが表示されます。

    APMトレース・イベントが正しくJFR記録に追加されていることを確認するには、JDK Mission Controlに接続し、「イベント・ブラウザ」でAPMトレースが表示されていることを確認します: 「APM OpenTracing」をクリックし、APMトレース・イベントが表示されることを確認します。

APMトレーサでのJFRイベントの構成

(オプション)これは、イベントのレポートをカスタマイズする場合のオプションのステップです。

JFR記録イベント分析を簡略化するために、各イベントはカテゴリまたはイベント・タイプ別に編成されます。

デフォルト・カテゴリ

APMトレーサでは、APM JFRイベントのデフォルト・カテゴリは、Span Operation Nameの内容(スパン内のnameというフィールド)を使用して取得されます。componentタグは移入できないため、デフォルト・カテゴリとして使用できません。

イベント

イベント・タイプを使用すると、JMCユーザー・インタフェース内でイベントを編成および分類できます。APMトレーサはスパンを取得すると、このスパンにイベントを生成できますが、その特定のイベントのイベント・タイプを決定する必要があります。

イベント・タイプの例として、サーブレット、jdbcおよびjax-rsがあります。

イベント・タイプ構成

イベント・タイプまたはカテゴリの構成を行うには、いくつかの方法があります。次に示す様々なユース・ケースを参照してください:

  • ケース1: componentタグ

    これがイベントを分類する最も単純な方法です。この方法を使用することをお薦めします。

    ほとんどのシナリオにおいて、Opentracingスパンにはcomponentというタグが含まれます。componentタグの値は、イベント・タイプの判別に使用されます。

    たとえば、次のスパンを見てみます:

    {  "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":[
      ]
    },

    この場合、生成されたイベントにはhelidon-webserverイベント・タイプが割り当てられます(それがcomponentタグの値であるため)。

  • ケース2: 他のタグ

    アプリケーションでcomponentタグを使用していないが、別のタグを使用しているか、タグを生成しているライブラリがある場合は、その別のタグからイベント・タイプを読み取るようにAPMトレーサを構成できます。

    たとえば、次のスパンでは、span.typeというタグからイベント・タイプを読み取ることができます:

    {  "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":[
      ]
    },

    この場合、javaアプリケーションの起動時に次のシステム・プロパティを使用して、span.typeタグからイベント・タイプを読み取るようにAPMトレーサを構成できます:

    java -Dcom.oracle.apm.agent.jfr.category.tag=span.type ...
  • ケース3: 使用可能なタグがない場合は操作名を使用する

    有用なカテゴリを持つタグがアプリケーションで使用されていない場合は、Operation Nameを使用してイベント・タイプを決定できますが、この方法はお薦めしません。

    JFRシステムでは、イベント・タイプの名前が有効なJava識別子である必要がありますが、Operation Nameにはスペースや他の不正な文字が含まれていることがよくあります。APMトレーサは、すべての不正な文字をアンダースコアで置換して、Operation Nameを有効な識別子に変換します。

    java -Dcom.oracle.apm.agent.jfr.category.default=ORACLE_APM_USE_SPAN_OPERATION_NAMES
    ノート

    Operation Nameは、カテゴリ・タグが存在しないか空の場合のみにのみ使用されます。

    これは単純な解決策とならない理由は、Operation NameにIDなどの一意のトークンが含まれていると、すべてのイベントが独自のイベント・タイプになるためです。さらに、Operation Nameを有効な識別子に変換すると、イベント・タイプを構成してイベントに必要なフィールドを設定する際に、さらに問題が発生します。また、構成は、変換されたOperation Nameに基づいて実行する必要があります。そうしない場合、Operation Nameの様々なバリアントを同じ方法で多数構成する必要があります。

  • ケース4: 使用可能なタグがなく、すべての操作名が一意である

    このケースでは、イベント・タイプの分類に使用できる情報はありません。これは、すべてのイベントが結果として同じイベント・タイプになるか、前述のユース・ケース3シナリオを使用して構成された場合はすべてのイベントが一意になるという、最悪のケース・シナリオです。唯一可能な方法は、このデフォルト・イベント・タイプの名前を選択できるようにすることです。これは次のように構成できます。

    java -Dcom.oracle.apm.agent.jfr.category.default=Unknown
    ノート

    デフォルトは、カテゴリ・タグが存在しないか空の場合のみにのみ使用されます。

    この場合、すべてのイベントは、Unknownというイベント・タイプ、または選択したカスタム値に設定されます。

イベント・タイプのフィールド

イベント・タイプごとに、そのイベント固有のデータを含む1つ以上のフィールドを追加できます。

イベント・タイプに追加できるフィールドのリストは、フィールドをJFRに公開できるようになってから、ACMLファイル内で構成する必要があります。フィールドごとに次の情報が必要です:
  • 名前。
  • タイプ(int、float、string、thread)。
  • ラベル。
  • 説明。
例については、traceIDの次のフィールド定義を参照してください:
- name: traceID
  type: String
  label: New Trace ID
  description: New Opentracing Trace ID

ACMLファイルの作成

このステップはオプションです。デフォルトの設定で期待どおりに動作していれば、このステップはスキップできます。

デフォルトの設定を変更して記録をカスタマイズする場合は、ACMLファイルを作成できます。

次の例は、Helidonマイクロサービス・コンテナの組込みのデフォルト設定を上書きしてJFRへのイベント・ロギングを構成するACMLファイルのフォーマットを示しています:

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

APMエージェントおよびAPMトレーサを使用する場合は、前述のフォーマットのACMLファイルを使用できます。APMトレーサの場合は、Helidon、Springboot、Micronautなどの任意のコンテナで動作します。

FAQ

  1. com.oracle.apm.agent.jfr.category.tagプロパティとcom.oracle.apm.agent.jfr.category.defaultプロパティの両方が設定されている場合、どちらの設定が優先されますか。

    両方に値が指定されている場合、まずスパン内にカテゴリ・タグがあるか調べます。見つかれば、それが使用されます。ない場合は、デフォルトが使用されます。

  2. APMトレーサの場合、構成ファイルは必須ですか。ファイルなしでプロパティを指定できますか。

    構成ファイルは必須ではありません。デフォルトで問題がなければ構成ファイルは不要ですが、自分でプロパティを指定することもできます。

  3. エントリが重複しているように見える場合があるのはなぜですか。たとえば、ACML構成ファイルの次のスニペットには、helidon-webserverエントリが2回出現します:
    eventTypes:
      helidon-webserver:
        name: helidon-webserver

    タグまたは操作名から読み取る/推測するのは、最初のhelidon-webserverエントリです。上の例のように、イベント・タイプがクリーンで準備しやすく直感的である場合、JFR記録に送信するのに同じイベント・タイプを使用できます。JMCではその形式で表示されます。

    ただし、operation nameの使用時に、dbクライアントからのJDBC問合せを表す、q_AxPsCbac9Ykp0HjpU+ENCiYHKl5HzMCmR02AfGzow3A=のようなイベント・タイプを取得する場合があります。この場合、JFR記録に送信された名前を直感的な名前に変更するために、次の例を使用できます:
    eventTypes:
      q_AxPsCbac9Ykp0HjpU+ENCiYHKl5HzMCmR02AfGzow3A=:
        name: jdbc-select-query
  4. イベント・タイプごとにrecordCallStackを指定できる場合、トップ・レベルrecordCallStackも必要になるのはなぜですか。

    コール・スタックの記録の柔軟性を最大限にするために、2つのユース・ケースをサポートしています。コール・スタック記録をグローバルにオフにしてから、特定のイベント・タイプに対して選択的にオンにできます。もう1つのオプションは、グローバルにオンにしてから、特定のイベント・タイプに対して選択的にオフにすることです。どちらのユース・ケースもサポートされているため、設定はトップ・レベルとイベント・レベルの両方にあります。

  5. まったく構成されていないスパンがいくつかあり、無視されています。構成せずにこれらのイベントを取得することは可能ですか。

    はい。メイン・トップ・レベル構成でallowUnconfiguredEvents: trueを設定すると、これらのイベントが取得されます。この場合、どのフィールドを収集するかがわかりません。デフォルト・フィールドのうち、traceIDspanIDparentSpanIDstartThreadおよびoperationNameのセットのみが収集されます。

  6. 操作名で定義されたカテゴリを使用するためにcom.oracle.apm.agent.jfr.category.default=ORACLE_APM_USE_SPAN_OPERATION_NAMESを使用した場合、構成ファイル内で操作名がイベント・タイプ名と正確に一致している必要がありますか。その場合、一意の操作名があると、操作ごとにイベント・タイプを指定する必要がありますか。

    はい、構成ファイル内のイベント・タイプ名と一致している必要があります。一意の操作名が多数ある場合でも、操作ごとにイベント・タイプを指定する必要があります。これは、これらのイベント・タイプそれぞれに異なるフィールド・セットを設定する必要があるためです。

  7. 操作名がJava識別子に変換されているため、そのイベント・タイプを構成できません。操作名が何に変換されたかはどのように判断できますか。

    不正な文字はすべてアンダースコアで置き換えられています。文字列を識別子に変換するためのサンプルJavaコードが必要な場合は、次のコードを使用できます。これは、APMが文字列の変換に使用するルーチンと同じです。
    // 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. 名前一致をRegExにできますか。

    いいえ。RegExはサポートされていません。