このページの例では、エージェント API の一般的な使用例を実装する方法について説明します。https://sdkdocs.appdynamics.com/java-agent-api/v20.6/ の javadoc を参照してください。

一般的な使用例

次に、エージェント API の一般的な使用例を示します。

同期ビジネストランザクションの開始と終了

次に、メソッド checkout() が呼び出されるたびに "Checkout" と呼ばれるビジネストランザクションが開始されるコード例を示します。ビジネストランザクションは、メソッドが戻ったときに終了します。try または finally ブロックでメソッド本体をカプセル化すると、メソッド自体が例外をスローした場合でも、ビジネストランザクションを終了します。それ以外の場合は、最後まで到達せずに終了します。

public String checkout(List<ItemOrders> orders) {
   Transaction transaction = null;
   try {
        transaction = AppdynamicsAgent.startTransaction("Checkout", null, EntryTypes.POJO, false);
 
        /*******************
         * Method Body Here
         *******************/
    } finally {
        if (transaction != null) {
           transaction.end();
        }
    }
}
CODE

または、try-with-resources パターンを使用することができます。

public String checkout(List<ItemOrders> orders) {
   try (Transaction transaction = AppdynamicsAgent.startTransaction("Checkout", null, EntryTypes.POJO, false)) {
        /*******************
         * Method Body Here
         *******************/
    }
}
CODE

この場合、try ブロックが終了すると、ビジネストランザクションが終了します。

非同期ビジネストランザクションの開始と終了

次に、メソッド checkoutAsync() が呼び出されるたびに「CheckoutAsync」と呼ばれるビジネストランザクションが開始されるコード例を示します。ビジネストランザクションに作成された送信元セグメントは、ビジネストランザクションでメソッド endSegment() が呼び出された場合、または try-with-resources 構成で使用されたときにクローズされた場合に終了しますtry/finally ブロックでメソッド本体をカプセル化すると、メソッド自体が例外をスローした場合でも、セグメントを終了します。それ以外の場合は、最後まで到達せずに終了します。

//The thread where the Business Transaction starts
public String checkoutAsync(List<ItemOrders> orders) {
   Transaction transaction = null;
   try {
        transaction = AppdynamicsAgent.startTransaction("CheckoutAsync", null, EntryTypes.POJO, true);
		//mark handoff to link this segment with the end segment
		transaction.markHandoff(commonPayload);

        /*******************
         * Method Body Here
         *******************/
    } finally {
        if (transaction != null) {
           transaction.endSegment();
        }
    }
}
CODE


または、try-with-resources パターンがサポートされています。

//The thread where the Business Transaction starts
public String checkoutAsync(List<ItemOrders> orders) {
   try (Transaction transaction = AppdynamicsAgent.startTransaction("CheckoutAsync", null, EntryTypes.POJO, true)) {
		//mark handoff to link this segment with the end segment
		transaction.markHandoff(commonPayload);

        /*******************
         * Method Body Here
         *******************/
    }
}
CODE


これにより、try ブロックが終了した場合にビジネストランザクションが開始されるスレッドのセグメントが終了します。ビジネストランザクション自体は、非同期ビジネストランザクションが終了するときのメソッドで終了する必要があります。

//The thread where the Business Transaction ends
public String checkoutAsyncEnd(List<ItemOrders> orders, Transaction transaction, Object commonPayload) {
   //link to the originating segment
   Transaction transactionSegment = AppdynamicsAgent.startSegment(commonPayload);

   /*******************
   * Method Body Here
   *******************/
   if (transactionSegment != null) {
      transactionSegment.endSegment();
   }
   if (transaction != null) {
      transaction.end();
   }
}
CODE

開始後のトランザクション名の設定

次に、開始後にトランザクション名を設定する例を示します。これは、アプリケーションで発生したイベントに基づいてトランザクションを分割する場合に役立ちます。

トランザクション名は、元のセグメントでの開始後に、非同期ハンドオフまたは終了が行われていない場合にのみ設定できます。

public String checkout(List<ItemOrders> orders) {
   AppdynamicsAgent.startTransaction("Checkout", null, EntryTypes.POJO, false);
   /*******************
    * Method Body Here
    *******************/
   if (orders.isEmpty()) {
   	   AppdynamicsAgent.setCurrentTransactionName("Empty Cart");
   }
   AppdynamicsAgent.getTransaction().end();
}
CODE

OOTB サーブレットの命名規則を使用したトランザクションの開始

次に、自動のサーブレットの命名規則を利用してトランザクションに名前を付ける例を示します。

public String checkout(List<ItemOrders> orders) {
	Map<String, String> headers = new HashMap<String, String>();
	headers.put("header1", "headerValue1");
	Map<String, String[]> parameters = new HashMap<String, String[]>();
	Map<String, Object> cookies = new HashMap<String, Object>();
	cookies.put("chip", "ahoy");
	ServletContext.ServletContextBuilder contextBuilder = new ServletContext.ServletContextBuilder()
        .withURL(new URL("https://www.yourstore.com/endpoint/to/checkout"))
        .withParameters(parameters)
        .withHeaders(headers)
        .withCookies(cookies)
        .withSessionAttributes(new HashMap<String, Object>())
        .withRequestMethod("GET")
        .withHostValue("hostValue")
        .withHostOriginatingAddress("hostOriginatingAddress");
	Transaction t = AppdynamicsAgent.startServletTransaction(contextBuilder.build(), EntryTypes.HTTP, null, false);
   /*******************
    * Method Body Here
    *******************/
   t.end();
}
CODE

exit コールの定義

別のプロセスに対して要求を行う inventoryServer.verifyQuantities(orders) では、その要求を exit コールとしてモニタできます。これにより、ダウンストリームサーバへのコールによるビジネストランザクションのモニタリングを継続し、リモートサービスで費やされた時間を特定することができます。このためには、次のようにメソッドを変更します。

public void verifyQuantities(List<ItemOrders> orders) {
    ExitCall exitCall = null;
    try {
        exitCall = AppdynamicsAgent.getTransaction().startExitCall("Quantity Check", "Inventory Server", ExitTypes.HTTP, false);
         
       /*******************
        * Method Body
        *******************/
    } finally {
        if (exitCall != null) {
            exitCall.end();
        }
    }
}
CODE

または、HTTP バックエンド検出ルールを使用する場合、startHttpExitCall メソッドを使用できます。

public void verifyQuantities(List<ItemOrders> orders) { 
    ExitCall exitCall = null; 
    try { 
         Map<String, String> identifyingProps = new HashMap<String, String>(); 
         URL url = new URL("https://www.appdynamics.com/solutions/microservices/"); 
           exitCall = AppdynamicsAgent.getTransaction().startExitCall(identifyingProps, url, false); 
           /******************* 
           * Method Body 
           *******************/ 
     } finally { 
        if (exitCall != null) { 
            exitCall.end();
        } 
     } 
}
CODE

上記のコード変更では、コントローラのリモートサービスとしてマニフェストを定義する exit コールを定義します。インストゥルメント化されたダウンストリーム階層への要求にタグを付けて追跡するには、相関ヘッダーを追加します。

public void verifyQuantities(List<ItemOrders> orders) {
    ExitCall exitCall = null;
    try {
        exitCall = AppdynamicsAgent.getTransaction().startExitCall("Quantity Check", "Inventory Server", ExitTypes.HTTP, false);
 
        // Generate the appdynamics correlation header
        String correlationHeader = exitCall.getCorrelationHeader();
 
        // ... Method code including request creation
 
        // Modify the request/payload to include the correlation header
        inventoryRequest.addHeader(AppdynamicsAgent.TRANSACTION_CORRELATION_HEADER, correlationHeader);
     
    } finally {
        if (exitCall != null) {
            exitCall.end();
        }
    }
}
CODE

次の例では、非同期 exit をインストゥルメント化する方法を示します。

public class StartEndAsyncExitCall {

    private void makeAsyncExitTransaction() throws Exception {
        System.out.println("Starting transaction");
        try (Transaction transaction = AppdynamicsAgent.startTransaction("StartEndAsyncExitCall", null, EntryTypes.POJO, true)) {
            Thread.sleep(1000);
            new TransactionEndingThread(transaction).start();
            System.out.println("Starting exitcall");
            ExitCall exitCall = null;
            exitCall = transaction.startExitCall("Custom", "Custom", ExitTypes.CUSTOM, true);
            new ExitCallEndingThread(exitCall).start();
        }
    }

    public class TransactionEndingThread extends Thread {
        Transaction transaction = null;

        TransactionEndingThread(Transaction transaction) {
            this.transaction = transaction;
        }

        public void run() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            transaction.end();
            System.out.println("Ending transaction");
        }
    }

    public class ExitCallEndingThread extends Thread {
        ExitCall exitCall = null;

        ExitCallEndingThread(ExitCall exitCall) {
            this.exitCall = exitCall;
        }

        public void run() {
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            exitCall.end();
            System.out.println("Ending exitcall");
        }
    }
}
CODE

非同期スレッドハンドオフの定義

チェックアウトメソッドでスレッドハンドオフが行われ、別のスレッドでモニタする一部のビジネスロジックが実行される場合も、ビジネストランザクションでワーカースレッドを登録します。

public String checkout(List<ItemOrders> orders) {
    Transaction transaction = null;
    try {
        transaction = AppdynamicsAgent.startTransaction("Checkout", null, EntryTypes.POJO, false);
 
        // ... Method code
 
        // Custom thread handoff using custom queue
        asyncTaskQueue.add(task);
         
    } finally {
        if (transaction != null) {
           transaction.end();
        }
    }
}
CODE


これをインストゥルメント化するには、スレッドハンドオフをマークするように add メソッドを変更してから、スレッドの実行を開始する新しいセグメントを開始します。

public class AsyncTaskQueue {
    public void add(Task task) {
        AppdynamicsAgent.getTransaction().markHandoff(task);
         
        /*******************
         * Method Body
         *******************/
}
CODE
public class Task {
    public void run() {
        Transaction transaction = null;
        try {
            transaction = AppdynamicsAgent.startSegment(this);
 
            /*******************
             * Method Body
             *******************/
        } finally {
            if (transaction != null) {
                transaction.endSegment();
            }
        }
    }
 
    public void cancel() {
        AppdynamicsAgent.cancelHandoff(this);
 
        /*******************
         * Method Body
         *******************/
    }
}
CODE


タスクオブジェクトは、セグメントを関連付けするエージェントによって使用されます。エージェント API を使用してスレッドセグメントを関連付けるには、エージェントが Executor モードで実行されている必要があります。

スナップショットまたは分析へのデータの追加

多くの場合、コードには、スナップショットに追加するのに役立つ興味深い値があります。これは、問題の根本原因の診断に役立ち、Splunk AppDynamics ビジネストランザクション分析に送信して、アプリケーションに関するリアルタイムのビジネス指向の質問に回答するのに役立ちます。この API を使用して報告されたデータは、メソッド呼び出しデータコレクタで収集されたものと同じように表示されます。

ビジネストランザクション分析のチェックアウト合計を報告し、APM スナップショットに表示されるようにするには、次のコードを使用します。

private static final Set<DataScope> dataScopeSet = new HashSet(Arrays.asList(DataScope.ANALYTICS, DataScope.SNAPSHOTS));
 
public String checkout(List<ItemOrders> orders) {
    Transaction transaction = null;
    try {
        transaction = AppdynamicsAgent.startTransaction("Checkout", null, EntryTypes.POJO, false);
 
        // ... Method code
 
        double shoppingCartTotal = total(orders);
        transaction.collectData("cart total", Double.toString(shoppingCartTotal), dataScopeSet);
         
    } finally {
        if (transaction != null) {
           transaction.end();
        }
    }
}
CODE

カスタム指標またはイベントの定義

カスタム指標として値を報告する場合にも役立ちます。

public String checkout(List<ItemOrders> orders) {
 
    // ... Method code
 
    double shoppingCartTotal = total(orders);
    AppdynamicsAgent.getMetricPublisher().reportSumMetric("Cart Total", (long) shoppingCartTotal);
 
}
CODE

メトリックのパブリッシュ時に、コード内でメトリック名とともにメトリックパスを Server|Component:<TierName>|Custom Metrics|<MetricName>, の形式で指定することをお勧めします。


カスタム指標とイベントの報告は、ビジネストランザクションのコンテキストに関係なく可能です。