Java エージェント API のインストゥルメンテーション SDK(iSDK)の部分を使用すると、実行時にアプリケーションのコードに適用するカスタム インストゥルメンテーションを作成できるので、コードをインストゥルメント化するための開発時の変更をする必要がありません。

iSDK を使用すると、必須の Java エージェント API を使用するインターセプタを実装し、カスタム インストゥルメンテーションを独自のアプリケーションまたはフレームワークに適用できます。このカスタム インストゥルメンテーションは、エージェントで使用可能な設定済みインストゥルメンテーションと連携します。

iSDK ユーザーは、sdk-plugins ディレクトリに Java エージェントとともに展開する場合、アプリケーション起動時にコードをインストゥルメント化するカスタムインターセプタ jar ファイルを別に作成する必要があります。カスタム インストゥルメンテーションを削除するには、エージェント展開からカスタムインターセプタ jar ファイルを削除します。

iSDK の使用

次の手順では、iSDK の使用方法の概要を説明します。

  1. 開発環境を設定します。
  2. プロジェクトを設定します。
  3. インターセプタを実装します。
  4. ファイルを作成します。
  5. 展開します。

開発環境の設定

iSDK を使用するには、iSDK ライブラリの外部の依存関係を含むコードを記述する必要があります。そのためには、次のツールが使用可能である必要があります。

  • Java IDE:Eclipse または IntelliJ。以下の例では、IntelliJ を使用します。
  • Gradle。

プロジェクトの設定

プロジェクトを設定するには、次の手順を実行します。

  1. IntelliJ で、作業用の新しい Gradle プロジェクトを作成します。build.gradle ファイルは、指定したプロジェクトディレクトリに作成されます。
  2. 次の項の手順に従って、プロジェクトの build.gradle ファイルに必要な情報を追加します。

依存関係のインストール

iSDK を使用するには、次のいずれかを実行します。

  • エージェント API jar に直接アクセスする
  • Maven Central からダウンロードする
  • Splunk AppDynamics ポータルからダウンロードする

ライブラリバージョンは、新しい API リリースごとに変更され、基本エージェントのバージョンには完全に関連付けられていません。

Maven Central で使用する場合は、次のいずれかでビルドファイルに依存関係を追加します。

  • Gradle:
dependencies {
    compile group: 'com.appdynamics.agent', name: 'agent-api', version: '20.6.0.30246'
}
CODE

または

  • Maven:
<dependency>
     <groupId>com.appdynamics.agent</groupId>
     <artifactId>agent-api</artifactId>
     <version>20.6.0.30246</version>
</dependency>
CODE

エージェント API の Javadoc については、https://sdkdocs.appdynamics.com/java-agent-api/v20.6/ [英語] を参照してください。

メソッドなどを自動入力したときに intellij でソースが適切に参照されるようにするには、intellij で gradle プロジェクトを更新し、"gradlew idea" を実行します。

この設定後に、Intellij を使用してクラスを作成し、iSDK テンプレートクラスを拡張して、欠落しているメソッドを自動入力できるようにする必要があります。

エージェント API を使用した iSDK の展開

iSDK とともにエージェント API の機能を利用する場合は、カスタムのインターセプタ jar を使用してパッケージ化する必要があります。Grade でこれを行うには、次の手順を実行します。

  1. iSDK の構成を作成します。

    configurations {
      isdk
    }
    CODE
  2. この構成にエージェント API の依存関係を追加します。

    dependencies {
        compile group: 'com.appdynamics.agent', name: 'agent-api', version: '20.6.0.30246'
    	isdk group: 'com.appdynamics.agent', name: 'agent-api', version: '20.6.0.30246'
    	…
    }
    CODE
  3. インターセプタ jar を生成するタスク内で、jar に AppdynamicsAgent クラスを含めます。

    jar {
      configurations.isdk.collect {
        it.isDirectory() ? from(it) : from(zipTree(it)) {
          include 'com/appdynamics/agent/api/AppdynamicsAgent.class'
        }
      }
      includeEmptyDirs = false
    }
    CODE

Maven でこれを行うには、AppdynamicsAgent クラスを jar に含めるように Ant タスクを記述する必要があります。

インターセプタの実装

クラスまたはメソッドの識別

すべての使用例について、インストゥルメント化するクラスとメソッドを識別する必要があります。これは、ユーザインターフェイスを使用してカスタム POJO インストゥルメンテーションを設定する場合にも当てはまりますが、その手法は SDK では大きく異なります。

カスタムのインターセプタとルールの作成

インストゥルメンテーション ロジックの実装

iSDK は、必要なカスタム インターセプタ ロジックでサブクラス化する必要がある AGenericInterceptor, というクラスを提供します。

エージェントは、エージェントの sdk-plugins ディレクトリに展開された .jar ファイルを調べて、AGenericInterceptor を拡張するクラスを探します。これらのクラスが、必要な抽象化メソッドを実装する必要があります。

すべてのインターセプタが実装する必要がある主要なメソッドの 1 つは、IRule インターフェイスを拡張するオブジェクトのリストを返す initializeRules メソッドです。これらの IRules は、指定されたインターセプタを適用する必要があるコード内の場所を表します(クラス名、メソッド名、メソッドパラメータなど)。

インターセプタがインストゥルメント化されたコードで使用されている java オブジェクトのいずれかでリフレクションを実行する必要がある場合は、実行時にこのようなリフレクションを容易にするために、インターフェイス IReflector が提供されています。

AGenericInterceptor で実装する重要なメソッド

  • initializeRules :インターセプタを配置する必要があるコード内の場所を記述するオブジェクトのリストを返します
  • onMethodBegin:このメソッドの本文に含まれるコードは、インストゥルメント化されたメソッドの実行前に実行されます
  • onMethodEnd:このメソッドの本文に含まれるコードは、インストゥルメント化されたメソッドの実行後に実行されます

AGenericInterceptorsエージェント API と組み合わせて、トランザクションの開始または終了や、スナップショットへのデータの追加などを行うことができます。

これらのインターセプタは、メソッドの最初または最後だけではなく、コード内の任意の場所に適用できます。また、ローカル変数情報を収集します。atLineNumberatFieldatLocalVariable、などのルールビルダーの特定のメソッドは、このさまざまな iSDK インターセプタにのみ適用されます。

  • 最上位の "sdk-plugins" ディレクトリに直接配置された jar もロードされます。
  • プラグイン jar でマニフェスト属性 "Plugin-Classes: <comma separated list of fully qualified class names>" を使用して、プラグインとしてロードする特定のクラスを指定できます。これにより、プラグイン jar にプラグインではない多くのクラスが含まれている場合に、jar のロードパフォーマンスが向上します。

Rule クラスと Rule.Builder クラスの使用

Rule は、インストゥルメント化する一連のクラスを定義します。iSDK コードは、initializeRules という名前のメソッドから Rule オブジェクトの java.util.List を返します。Rulesビルダーパターンを使用して作成され、 Rule.Builder オブジェクトは一致文字列を使用して作成されます。

Rule.Builder builder = new Rule.Builder("com.mynamespace.MyClass");

この項で参照されているすべてのクラスの javadocs を参照してください。

これは、UI で実行する必要がある内容に似ています。たとえば、[Add Information Point] 設定画面では、具象クラス名、抽象クラス名、インターフェイス名、注釈名のいずれかで、照合する名前を指定する必要があります。Rule.Builder コンストラクタへの引数は、(Class 一致テキストボックスの)UI で指定するものと同じです。


その後、Rule.Builder クラスで API を呼び出すことで Rule.Builder を変更します。Rule.Builder は、コードをコンパクトにできるようにフルーエントスタイルをサポートしています。

次のものが必要になります。

  • クラス照合文字列:コンストラクタで次に指定されますRule.Builder
  • クラス照合タイプ:builder.setClassMatchType を使用して SDKClassMatchType を設定します
  • クラス照合文字列の照合タイプ:builder.classStringMatchType を使用してメソッドの SDKStringMatchType を設定します
  • 次を使用したメソッド照合文字列。builder.setMethodMatchString
  • メソッド照合タイプ:builder.methodStringMatchType を使用してメソッドの SDKStringMatchType を設定します

任意のインターセプタを作成するための initializeRules() メソッドのスクリーンショットを次に示します。次の点に注意してください。

  • このスタイルは、フルーエントと反復を組み合わせたものです(行には連結された呼び出しがありますが、複数の行が使用されています)
  • クラス照合は、具象クラス(classStringMatchTypeSDKClassMatchType.MATCHES_CLASS および SDKStringMatchType.EQUALS)と完全に一致するクラス名を対象にしています
  • メソッド照合は、完全に一致するメソッド名文字列(methodStringMatchTypeSDKStringMatchType.EQUALS)を対象にしています

Arbitrary Interceptor Method

インターセプタロジックの実装

カスタムインターセプタがヒットしたときに実行される Java コードは、インターセプタオブジェクトの onMethodBeginonMethodEnd メソッドで提供されます。

エージェント API を活用する単純なインターセプタのコード例を次に示します。

public class SampleGenericInterceptor extends AGenericInterceptor {

    public SampleGenericInterceptor() {
        super();
    }

    @Override
    public List<Rule> initializeRules() {
        List<Rule> rules = new ArrayList<Rule>();
        rules.add(new Rule.Builder("Main").methodMatchString("genericInterceptorTarget").build());
        return rules;
    }

    public Object onMethodBegin(Object invokedObject, String className, String methodName, Object[] paramValues) {
        System.out.print("In begin");
		AppdynamicsAgent.startTransaction("SampleGenericInterceptorBT", null, EntryTypes.POJO, false);
        Map<String, String> keyVsValue = new HashMap<String, String>();
        keyVsValue.put("foo", "bar");
        AppdynamicsAgent.getEventPublisher().publishEvent("an event happened", "INFO", "AGENT_STATUS", keyVsValue);
        return null;

    }

    public void onMethodEnd(Object state, Object invokedObject, String className, String methodName,
            Object[] paramValues, Throwable thrownException, Object returnValue) {
        System.out.print("In end");
		Transaction currentTransaction = AppdynamicsAgent.getTransaction();
		Set<DataScope> dataScopes = new HashSet<DataScope>();
		dataScopes.add(DataScope.SNAPSHOTS); // collect data for BT snapshot.
		currentTransaction.collectData("key", "value", dataScopes);
		currentTransaction.end();
    }
}
CODE

IReflector インターフェイスの使用

すべての iSDK クラスには、IReflector という名前のツールボックス インターフェイスへのアクセス権があります。このインターフェイスは、Java リフレクションの使用を可能にする機能を提供します。いずれかのテンプレートクラスを拡張するクラス内で、ユーザは IReflectionBuilder のインスタンスを取得するために getNewReflectionBuilder() を呼び出すことができます。  

getNewReflectionBuilder() は、プラグインクラスのコンストラクタで呼び出す必要があります。別の場所で呼び出された場合は、NullPointerException が発生することがあります。

このインターフェイスは、次のメソッドをサポートしています。

/**
* load a class. classLoader specified in the IReflector.execute method
**/
IReflectionBuilder loadClass(String className);
/**
* Create a new object
* @param className class to create
* @param argTypes argument types
* @return this
*/
IReflectionBuilder createObject(String className, String... argTypes);
/**
* Invoke a static method
* @param methodName method to invoke
* @param searchSuperClass search super classes for the method. Else only declared methods are called
* @param argTypes for overloaded methods
* @return this
*/
IReflectionBuilder invokeStaticMethod(String methodName, boolean searchSuperClass, String... argTypes);
/**
* Similar to invoke static method, invoke a instance method
* @param methodName method to invoke
* @param searchSuperClass search super classes for the method. Else only declared methods are called
* @param argTypes for overloaded methods
* @return this
*/
IReflectionBuilder invokeInstanceMethod(String methodName, boolean searchSuperClass, String... argTypes);
/**
* Access a field
* @param fieldName field name to access
* @param searchSuperClass should search super class for the field name
* @return this
*/
IReflectionBuilder accessFieldValue(String fieldName, boolean searchSuperClass);
These can be called in any order, essentially forming a getter chain. After crafting your chain of calls, the build() method must be called, returning an IReflector.
The IReflector is used by invoking its execute() method:
/**
* Execute the reflector chain
* @param classLoader required - classloader referenced to load classes
* @param target The steps will start executing on this object. null if first step is loadClass or staticMethod
* @param params params to be passed to the steps
* @return returns with correct cast
* @throws ReflectorException
*/
<E> E execute(ClassLoader classLoader, Object target, Object[]... params) throws ReflectorException;
/**
* Execute the reflector chain
* @param classLoader required - classloader referenced to load classes
* @param target The steps will start executing on this object. null if first step is loadClass or staticMethod
* @param params params to be passed to the steps
* @return returns with correct cast
* @throws ReflectorException
*/
<E> E execute(ClassLoader classLoader, Object target, OperationParams params)
throws ReflectorException;

多くの場合、これらのリフレクタの使用は、必要な機能(ペイロードからの値の抽出や、相関ヘッダーによるオブジェクトの修飾など)の取得のために非常に重要です。

Java エージェント API ドキュメンテーション

Java エージェントの「Cisco AppDynamics APM Agent API」を参照してください。