アプリケーションへのAppDynamicsヘッダーファイルの追加

SDK をダウンロードすると、C/C++ アプリケーションに AppDynamics インストゥルメンテーションを追加する準備ができます。最初のステップでは、main 関数ファイルの上に AppDynamics ヘッダーファイルを追加します。

#include <path_to_SDK>/sdk_lib/appdynamics.h
CODE

コントローラ構成の初期化

コントローラ情報の設定では、エージェントからコントローラへの接続が許可されています。一部の設定はすべてのアプリケーションで必須ですが、その他の設定は特定のタイプのアプリケーション環境でのみ必要です。たとえば、エージェントからネットワーク内の内部プロキシ経由でコントローラに接続する必要がある場合は、プロキシの接続を設定する必要があります。設定のリストおよび、必要な設定については、「C/C++ SDK 参考資料」を参照してください。

アプリケーションで、必須の設定に値を割り当てます。

コントローラの接続情報を設定する例:

const char APP_NAME[] = "SampleC";
const char TIER_NAME[] = "SampleCTier1";
const char NODE_NAME[] = "SampleCNode1";
const char CONTROLLER_HOST[] = "controller.somehost.com";
const int CONTROLLER_PORT = 8080;
const char CONTROLLER_ACCOUNT[] = "customer1";
const char CONTROLLER_ACCESS_KEY[] = "MyAccessKey";
const int CONTROLLER_USE_SSL = 0; 
CPP

デフォルトのアプリケーション コンテキストを作成するには、コントローラ設定で appd_config struct を宣言します。

例: 

struct appd_config* cfg = appd_config_init(); // appd_config_init() resets the configuration object and pass back an handle/pointer
appd_config_set_app_name(cfg, APP_NAME);
appd_config_set_tier_name(cfg, TIER_NAME);
appd_config_set_node_name(cfg, NODE_NAME);
appd_config_set_controller_host(cfg, CONTROLLER_HOST);
appd_config_set_controller_port(cfg, CONTROLLER_PORT);
appd_config_set_controller_account(cfg, CONTROLLER_ACCOUNT);
appd_config_set_controller_access_key(cfg, CONTROLLER_ACCESS_KEY);
appd_config_set_controller_use_ssl(cfg, CONTROLLER_USE_SSL);
CPP

SDK の初期化

main 関数で、次の初期化関数を呼び出します。

  1. 前のセクションで示したとおりに config 構造体を初期化します。
  2. 構成構造体を appd_sdk_init() に渡して SDK を初期化します。

appd_sdk_init() からゼロが返された場合は、SDK が正常に初期化されています。ゼロ以外の場合は、SDK がコントローラに達することができなかったために失敗したことを示します。

次の例は、SDK を初期化する方法を示しています。

int initRC = appd_sdk_init(cfg);

if (initRC) {
      std::cerr <<  "Error: sdk init: " << initRC << std::endl;
      return -1;
} 
CPP

appd_sdk_init() および fork() を含むすべての SDK コールは、分岐されたプロセスでのみ発生し、親プロセスでは発生しません。子コールはそれぞれ独立して動作する必要があり、プロセスと他の SDK でインストゥルメント化された子プロセス間でハンドルを共有できません。

代替アプリケーション コンテキストの作成

SDK は、デフォルトのアプリケーション コンテキストには名前が関連付けられていないことを前提としています。 

デフォルトのアプリケーション コンテキストを作成するには、デフォルトの構成構造体へのポインタを返す appd_config_init() コマンドを使用します。次に、setter コマンドを使用して構造体内のフィールドを変更します。関連するすべてのフィールドを設定したら、appd_sdk_init() コールを使用してデフォルトのアプリケーション コンテキストで SDK を初期化します。

他のすべてのアプリケーション コンテキストは、関連付けられる名前と一連の個別の setter メソッドを使用して作成されます。 

代替アプリケーション コンテキストを作成するには、appd_context_config_init() コマンドに代替アプリケーション コンテキストの名前を渡します。これは、代替アプリケーション コンテキスト構成構造体へのポインタを返します。次に、_context_ setter コマンドを使用して、構造体内のフィールドを変更します。関連するすべてのフィールドを設定したら、appd_sdk_add_app_context() コールを使用して SDK を初期化し、代替アプリケーション コンテキスト構造体ポインタを渡します。

// create the alternate application context
appd_context_config* cfg2 = appd_context_config_init("My_Context");
...

// add additional setter commands to initialize the alternate application context
appd_context_config_set_controller_account(cfg2, ac.second.ac_account_get().c_str());
appd_context_config_set_controller_access_key(cfg2, ac.second.ac_access_key_get().c_str());
appd_context_config_set_controller_host(cfg2, ac.second.ac_host_get().c_str());
appd_context_config_set_controller_port(cfg, ac.second.ac_port_get());
appd_context_config_set_controller_use_ssl(cfg2, ac.second.ac_use_ssl_get() ? 1 : 0);
appd_context_config_set_app_name(cfg2, ac.second.ac_app_get().c_str());
appd_context_config_set_tier_name(cfg2, ac.second.ac_tier_get().c_str());
appd_context_config_set_node_name(cfg2, ac.second.ac_node_get().c_str());

// initialize the alternate application context
appd_sdk_add_app_context(cfg2);
CODE

ビジネストランザクションの作成

appd_bt_begin() コールと appd_bt_end() コールの間に、モニタ対象のリクエストで構成されるコードを囲んで、ビジネストランザクションを定義します。そのビジネストランザクションが影響を受ける後続のルーチンで使用されるハンドルが appd_bt_begin() から返されます。

アップストリームのビジネストランザクションと相関するビジネストランザクションを作成する場合は、アップストリームのトランザクションの相関ヘッダーを渡して、作成を新しいトランザクションと関連付けることができます。「C/C++ SDK 参考資料」の appd_exitcall_get_correlation_header() を参照してください。トランザクションが別のトランザクションと相関する必要がない場合は、相関ヘッダーパラメータとして NULL を渡します。

オプションで、ビジネス トランザクション ハンドルを GUID とともにグローバル ハンドル レジストリに格納すると、後で appd_bt_store() を使用して簡単に取得できます。appd_bt_get() によって、グローバル ハンドル レジストリからハンドルを取得します。

次に、ビジネストランザクションの設定例を示します。

// start the "Checkout" transaction
appd_bt_handle btHandle = appd_bt_begin("Checkout", NULL);

// Optionally store the handle in the global registry
appd_bt_store(btHandle, my_bt_guid);
... 

// Retrieve a stored handle from the global registry
appd_bt_handle myBtHandle = appd_bt_get(my_bt_guid);
... 

// end the transaction
appd_bt_end(btHandle);
CPP

トランザクションの開始と終了の間に、ビジネストランザクションへのエラーの追加、トランザクション スナップショット属性の定義、バックエンドと終了コールの追加などの操作を実行できます。 

appd_bt_end() へのコールによってビジネストランザクションが終了すると、エージェントはビジネストランザクションのメトリックの報告を停止します。

代替アプリケーション コンテキストを使用したビジネストランザクションの作成

appd_bt_begin_with_app_context() コールと appd_bt_end() コールを使用すると、代替アプリケーション コンテキストでビジネストランザクションを作成できます。appd_bt_begin() に渡されるパラメータに加えて、appd_bt_begin_with_app_context() は、appd_context_config_init() へのコールで定義されたアプリケーション コンテキスト名の文字列も引数として受け取ります。

appd_bt_begin_with_app_context() は、そのビジネストランザクションに影響する後続のルーチンで使用するハンドルを返します。 

次の例は、代替アプリケーション コンテキストでビジネストランザクションを設定する方法を示しています。

// create the alternate application context
appd_context_config* cfg2 = appd_context_config_init("My_Context");
...


// add additional setter commands to initialize the alternate application context
appd_context_config_set_controller_account(cfg2, ac.second.ac_account_get().c_str());
appd_context_config_set_controller_access_key(cfg2, ac.second.ac_access_key_get().c_str());
appd_context_config_set_controller_host(cfg2, ac.second.ac_host_get().c_str());
appd_context_config_set_controller_port(cfg, ac.second.ac_port_get());
appd_context_config_set_controller_use_ssl(cfg2, ac.second.ac_use_ssl_get() ? 1 : 0);
appd_context_config_set_app_name(cfg2, ac.second.ac_app_get().c_str());
appd_context_config_set_tier_name(cfg2, ac.second.ac_tier_get().c_str());
appd_context_config_set_node_name(cfg2, ac.second.ac_node_get().c_str());

// initialize the alternate application context
appd_sdk_add_app_context(cfg2);


// start the "Checkout" transaction with the alternate application context
appd_bt_handle btHandle = appd_bt_begin_with_app_context("My_Context", "Checkout", NULL);
 
// end the transaction
appd_bt_end(btHandle);
CODE

appd_bt_end() へのコールによってビジネストランザクションが終了すると、エージェントはビジネストランザクションのメトリックの報告を停止します。トランザクションの開始と終了の間に、ビジネストランザクションへのエラーの追加、トランザクション スナップショット属性の定義、バックエンドと終了コールの追加などの操作を実行できます。 

ビジネストランザクションエラーの追加

appd_bt_add_error() を使用してビジネストランザクションのエラーを報告します。この関数の markBTAsError パラメータを設定すると、トランザクションはエラーが発生した際にエラートランザクションとして報告されます。{{appd_bt_add_error,}}, 関数の場合、コントローラデータベースは 5000 文字を超えるログメッセージを切り捨てます。

SDK には、エラーレベルを APPD_LEVEL_NOTICEAPPD_LEVEL_WARNING、または APPD_LEVEL_ERROR として分類する enum が用意されています。

ビジネストランクションスナップショットの管理

エージェントは、ビジネストランザクションをモニタする際、特定の時点でのビジネストランザクションのインスタンスを示すトランザクション スナップショットを自動作成します。トランザクションスナップショットには多くの詳細が含まれるため、パフォーマンス低下時のトラブルシューティングに大変役立ちます。

スナップショットを作成するには、ビジネストランザクションを作成する以外に変更することは何もありませんが、以下を実行するコールを追加できます。

  • スナップショットが取得されているかを確認
  • スナップショットに追加データを提供
  • スナップショットにURLを設定

エージェントが現在スナップショットを取得しているかを確認

エージェントは、コストが高いため、スクリーンショットを常に収集しません。デフォルトではスナップショットは10分ごとに収集されますが、このスケジュールは構成可能です。「スナップショットの定期的な収集頻度の構成」を参照してください。

エージェントがスナップショットを収集している場合に 0 ではない数字を返す appd_bt_is_snapshotting() を使用して、スナップショットが現在取得されているかどうかを確認できます。主に、スナップショットのユーザーデータ収集のための無駄なオーバーヘッドや、現在スナップショットが収集されていない場合にスナップショットURLを設定することを回避するために使用します。

ビジネストランザクションユーザーデータの追加

必要に応じて、トランザクション スナップショットにデータを追加できます。たとえば、多数のエラーが発生しているユーザ、応答時間が遅くなっているリージョンやどのメソッドが遅いのかを把握できます。データは、コントローラ UI のトランザクション スナップショットの [USER DATA] タブに表示されます。

スナップショットが発生しているときは、appd_bt_add_user_data() を使用してスナップショットに収集させるデータのキーと値を渡します。{{appd_bt_add_user_data,}} 関数の場合、コントローラデータベースは 5000 文字を超えるログメッセージを切り捨てます。

スナップショットURLの追加

スナップショットの URL を使用すると、コントローラユーザはスナップショットを他のユーザと共有できます。appd_bt_set_url() を使用して、URL を現在のスナップショットに設定できます。

スナップショットの設定例

void setSnapshotAttributes(appd_bt_handle btHandle, int minute, int halfsec)
{
    // do this only if the agent is collecting a snapshot
    if (appd_bt_is_snapshotting(btHandle))
    {
        char nameBuf[30];
        char valueBuf[30];
        // add custom data to the snapshot
        snprintf(nameBuf, sizeof(nameBuf), "BT:%p\n", btHandle);
        snprintf(valueBuf, sizeof(valueBuf), "Minute:%d Second:%d\n", minute, halfsec/2);
        appd_bt_add_user_data(btHandle, nameBuf, valueBuf);

        static int snapCount = 0;
        int switchVal = snapCount % 4;

        // report errors, but only ERROR_LEVEL errors are marked as error transactions
        if (switchVal)
        {
            appd_error_level errorLevel;
            bool markBtAsError;
            switch (switchVal)
            {
            case 1:
                errorLevel = APPD_LEVEL_NOTICE;
                markBtAsError = false;
                snprintf(nameBuf, sizeof(nameBuf), "NOTICE BT:%p M:%d S:%d\n", btHandle, minute, halfsec/2);
                break;
            case 2:
                errorLevel = APPD_LEVEL_WARNING;
                markBtAsError = false;
                snprintf(nameBuf, sizeof(nameBuf), "WARNING BT:%p M:%d S:%d\n", btHandle, minute, halfsec/2);
                break;
            case 3:
                errorLevel = APPD_LEVEL_ERROR;
                markBtAsError = true;
                snprintf(nameBuf, sizeof(nameBuf), "ERROR BT:%p M:%d S:%d\n", btHandle, minute, halfsec/2);
                break;
            }
            appd_bt_add_error(btHandle, errorLevel, nameBuf, markBtAsError, markbtaserror);
        }
        snapCount++;
        // set the snapshot url
        snprintf(nameBuf, sizeof(nameBuf), "http://bt-%p.com", btHandle);
        appd_bt_set_url(btHandle, nameBuf);
    }
}
CPP

バックエンドの作成

バックエンドは、データベースまたはアプリケーションが使用するメッセージキュー、HTTPサービス、またはキャッシュサービスなどのリモートサービスです。バックエンドコンポーネント自体はアプリケーションエージェントにより監視されませんが、エージェントはインストゥルメント化されたサーバーからの呼び出しを監視します。インストゥルメント化された環境でエージェントがバックエンドを検出できるよう、バックエンドを作成する必要があります。以下が必要となります。

  • バックエンドの宣言
  • 識別プロパティの設定
  • 必要に応じて、AppDynamics UIにおけるバックエンド表示方法の構成
  • インストゥルメント化されたアプリケーションへのバックエンドの追加

バックエンドの宣言

エージェントが検出できるように、appd_backend_declare() を使用してバックエンドを宣言する必要があります。バックエンドを宣言した後は、バックエンドを単一SDKインスタンス内の他のビジネストランザクションが使用している場合、再度宣言する必要はありません。バックエンドは、「C/C++ SDK 参考資料」の「終了コールタイプ」のリストにあるサポートされているタイプのいずれかである必要があります。

バックエンドの識別

バックエンドには、appd_backend_set_identifying_property() を使用して設定する識別プロパティもあります。 これらのプロパティは、バックエンドのタイプおよび表示する情報のタイプによって異なります。コントローラでは、バックエンドのダッシュボードに識別プロパティが表示されます。追加するバックエンドのタイプに少なくとも 1 つの識別プロパティを設定する必要があります。 

次に、ActiveMQのコントローラUIのバックエンドプロパティを示します。

Backend Properties

ティアへの転換

アプリケーションへの追加

バックエンドを宣言して構成したら、アプリケーションに追加してエージェントが検出できるようにします。

バックエンドの例

次のリストに、データベースバックエンドの設定例を示します。 

// declare a backend, only once for this SDK instance
const char backendOne[] = "first backend";
appd_backend_declare(APPD_BACKEND_HTTP,  backendOne);

// set the host property
rc = appd_backend_set_identifying_property(backendOne, "HOST", "sqs-us-west-hostname");
if (rc) {
   std:cerr << "Error: appd_backend_set_identifying_property: " << rc << ".";
   return -1;
}

// do not resolve the backend to the tier
rc = appd_backend_prevent_agent_resolution(backendOne);
if (rc) {
   std:cerr << "Error: appd_backend_prevent_agent_resolution: " << rc << ".";
   return -1;
}

// add the backend
rc = appd_backend_add(backendOne);
if (rc)
{
   std:cerr << "Error: appd_backend_add: " << rc << ".";
   return -1;
} 
CPP

終了コールの管理

アプリケーションが別のコンポーネント(検出されたバックエンドまたは別のアプリケーションサーバ)を呼び出すと、エージェントはこれらの呼び出しに関するメトリックを報告します。

appd_exitcall_begin() コールと appd_exitcall_end() コールの間に終了コールを構成するコードを囲み、終了コールを定義します。appd_exitcall_begin() はその終了コールに影響を与える後続のルーチンで使用するハンドルを返します。終了コールは、ビジネストランザクションのコンテキスト内で発生します。

オプションで、終了コールハンドルを GUID とともにグローバル ハンドル レジストリに格納すると、後で appd_exitcall_store() を使用して簡単に取得できます。appd_exitcall_get() によって、グローバル ハンドル レジストリからハンドルを取得します。

ビジネス トランザクション ハンドルおよび宛先バックエンドを appd_exitcall_end() に渡します。

必要に応じて、任意の文字列として終了コールに詳細を追加することができます。詳細はコントローラUIのトランザクションスナップショットの終了コール詳細に報告されます。

Exit Call Details

appd_exitcall_add_error() を使用して終了コールにエラーを追加することもできます。エラーレベルには列挙型を使用します。また、エラーメッセージを追加することもできます。

単純な終了コールの例

// start the exit call to backendOne
appd_exitcall_handle ecHandle = appd_exitcall_begin(btHandle, backendOne);

...

// optionally store the handle in the global registry
appd_exitcall_store(ecHandle, my_ec_guid);

...
// retrieve a stored handle from the global registry
appd_exitcall_handle myEcHandle = appd_exitcall_get(my_ec_guid);
 
// set the exit call details
rc = appd_exitcall_set_details(ecHandle, "backend ONE");
if (rc) {
   std:cerr << "Error: exitcall details1";
   return -1;
}

// add an error to the exit call
appd_exitcall_add_error(ecHandle, APPD_LEVEL_ERROR, "exitcall1 error!", true);

// end the exit call
appd_exitcall_end(ecHandle)
CPP

他のビジネストランザクションとの相関

相関ヘッダーには、エージェントが複数のティアにわたるビジネストランザクションのフローを継続できるようにする情報が含まれています。

SDK は、他の SDK や特定のタイプのエントリポイントとイグジットポイントに自動で相関を実行する他の AppDynamics エージェント(Java、.NET、PHP など)と相互に関連付けることができます。 

アップストリームティアとの相関

インストゥルメント化されたプロセスが、自動相関に対応するアップストリームエージェントからの継続的なトランザクションを受信したら、以下を行います。

  1. サードパーティの http_get_header() 関数を使用して、受信 HTTP ペイロードから APPD_CORRELATION_HEADER_NAME という名前のヘッダーを抽出。

  2. ヘッダーを appd_bt_begin() に渡す。例:

    const char* hdr = http_get_header(req, APPD_CORRELATION_HEADER_NAME);
    appd_bt_handle bt = appd_bt_begin("fraud detection", hdr);
    CPP

http_get_header() 関数で取得したヘッダーが有効な場合、appd_bt_begin() コールにより開始したビジネストランザクションは、アップストリームサービスにより開始したビジネストランザクションを継続します。

ダウンストリームティアとの相関

ダウンストリーム エージェントは、HTTP ペイロード内にある singularityheader  という名前の相関ヘッダーをモニタしています。

SDKエージェントが、自動相関に対応するダウンストリームエージェントへの終了コールを行っている場合は、以下を実行します。

  1. APPD_CORRELATION_HEADER_NAME を使用して相関ヘッダーの名前を設定。
  2. 終了コールを開始。
  3. appd_exitcall_get_correlation_header() 関数を使用して終了コールから相関ヘッダーを取得。
  4. サードパーティのHTTP関数を使用して、HTTP POST要求を準備。
  5. ステップ 3 で取得した相関ヘッダーの値とともに、APPD_CORRELATION_HEADER_NAME という名前のヘッダーを HTTP 要求の送信ペイロードに挿入。
  6. リクエストを実行することができます。 {{2}}は特定の属性を識別し、 {{3}} はこの属性に割り当てる新規の値を指定します。

    const char* const APPD_CORRELATION_HEADER_NAME = "singularityheader";
    
    appd_exitcall_handle inventory = appd_exitcall_begin(bt, "inventory");
    const char* hdr = appd_exitcall_get_correlation_header(inventory);
    http_request req;
    http_init(&req, HTTP_POST, "https: //inventory/holds/%s", sku);
    http_set_header(&req, APPD_CORRELATION_HEADER_NAME, hdr);
    http_perform(&req);
    
    ...
    CPP

cURLダウンストリーム相関の例

以下は、cURL ライブラリを使用してダウンストリーム トランザクションと相関する例です。

#include <curl/curl.h>
. . . 
. . .
// get the correlation header into the response
class LibcurlURLGet
{
public:
    LibcurlURLGet(const std::string& url) : url(url), curlHandle(NULL) {}
    std::string GetResponse(const char* correlationHeader)
    {
        CURLcode res;
        Response response;
        curlHandle = curl_easy_init();
        if (curlHandle)
        {
            curl_easy_setopt(curlHandle, CURLOPT_URL, url.c_str());
            curl_easy_setopt(curlHandle, CURLOPT_WRITEFUNCTION, WriteDataCallback);
            curl_easy_setopt(curlHandle, CURLOPT_WRITEDATA, &response);
            if(correlationHeader && strlen(correlationHeader))
            {
 
// start new added code
 
                std::string singularityHeader(APPD_CORRELATION_HEADER_NAME);
                singularityHeader.append(": ");
                singularityHeader.append(correlationHeader);
 
// end new added code
 
                curl_slist* slistNewHeaders = 0;
                slistNewHeaders = curl_slist_append(slistNewHeaders, correlationHeader);
                curl_easy_setopt(curlHandle, CURLOPT_HTTPHEADER, slistNewHeaders);
            }
            res = curl_easy_perform(curlHandle);
            if(res != CURLE_OK)
            {
            }
        }
        curl_easy_cleanup(curlHandle);
        return response.GetResponseString();
    }
private:
    class Response
    {
    public:
        std::string GetResponseString()
        {
            return sResponse;
        }
        void AppendResponse(void* ptr, size_t sizeBytes)
        {
            sResponse.append((char*)ptr, sizeBytes);
        }
    private:
        std::string sResponse;
    };
    static size_t WriteDataCallback(void* ptr, size_t size, size_t nmemb, Response* response)
    {
        response->AppendResponse(ptr, size * nmemb);
        return size * nmemb;
    }
    std::string url;
    CURL* curlHandle;
};
 
...
// start an exit call from the current transaction 
appd_exitcall_handle ecHandle1 = appd_exitcall_begin(btHandle1, tier2);

...
// before exiting get the correlation header
const char* corrHeader1 = appd_exitcall_get_correlation_header(ecHandle1);

// put the correlation in the HTTP response
std::string response = urlGet.GetResponse(corrHeader1);

...
// start the next business transaction to correlate with the previous one
appd_bt_handle btHandle = appd_bt_begin("Verify", response)

CPP

カスタムメトリックの作成

ビジネストランザクションのコール数や応答時間などのビルトインメトリックを補完するカスタムメトリックを作成できます。複数のアプリケーション コンテキストのメトリックも作成できます。

カスタムメトリックはアプリケーション コンテキストに依存します。複数のコンテキストがある状況では、関連するアプリケーション コンテキストに適用するカスタムメトリックに正しいコンテキスト名を指定する必要があります。代替アプリケーション コンテキストの作成」を参照してください。

ノードでカスタムメトリックを作成すると、カスタムメトリックは階層内の他のすべてのノードに表示されます。

たとえば、デフォルトのアプリケーション コンテキストでは、名前としてヌルポインタまたは空の文字列を使用します。appd_sdk_init メソッドは、SDK に対してコントローラに接続し、デフォルトのアプリケーション コンテキストを作成するように指示します(名前は指定されません)。

struct appd_config* cfg = appd_config_init();
appd_config_set_controller_host(cfg, host.c_str());
appd_config_set_controller_port(cfg, port);
appd_config_set_controller_account(cfg, account_name.c_str());
appd_config_set_controller_access_key(cfg, access_key.c_str());
appd_config_set_controller_use_ssl(cfg, useSSL?1:0);
appd_config_set_app_name(cfg, app_name.c_str());
appd_config_set_tier_name(cfg, tier_name.c_str());
appd_config_set_node_name(cfg, node_name.c_str());
appd_sdk_init(cfg);
CODE

代替アプリケーション コンテキストを指定するには、(デフォルトのヌルポインタではなく)名前文字列を指定する必要があります。代替アプリケーション コンテキストを作成するには、appd_sdk_add_appd_context メソッドを使用します。次の例では、「context2」という代替アプリケーション コンテキストを作成します。この名前文字列を使用して、実際の構成構造体ではなく、カスタムメトリックを作成します。 

const char* name = "context2";
struct appd_context_config* cfg2 = appd_context_config_init(name)); 
appd_context_config_set_controller_account(cfg2, ac.second.ac_account_get().c_str());
appd_context_config_set_controller_access_key(cfg2, ac.second.ac_access_key_get().c_str());
appd_context_config_set_controller_host(cfg2, ac.second.ac_host_get().c_str());
appd_context_config_set_controller_port(cfg, ac.second.ac_port_get());
appd_context_config_set_controller_use_ssl(cfg2, ac.second.ac_use_ssl_get() ? 1 : 0);
appd_context_config_set_app_name(cfg2, ac.second.ac_app_get().c_str());
appd_context_config_set_tier_name(cfg2, ac.second.ac_tier_get().c_str());
appd_context_config_set_node_name(cfg2, ac.second.ac_node_get().c_str());
 
appd_sdk_add_app_context(cfg2);
CODE

カスタムメトリックパスは、同じコントローラに移動する場合と移動しない場合があります。個別のノードのビジネストランザクションと同様に、プログラムは異なるノードの 2 つのビジネストランザクションを処理できます。1 つはデフォルトのアプリケーション コンテキストに合わせ、もう 1 つは代替アプリケーション コンテキストに合わせます。メソッド文字列が Custom Metric| ではなく Custom Metrics| で始まるように指定する必要があります。

カスタムメトリックを作成する場合、次のメソッドを使用できます。

  • appd_custom_metric_add() 

  • appd_custom_metric_report()

appd_custom_metric_add() メソッドは、デフォルトコンテキストにカスタムメトリックを登録します。

appd_custom_metric_add(nullptr, "Custom Metrics|my_default_custom_metric" , time_rollup_type, cluster_rollup_type, hole_handling_type);
CODE

appd_custom_metric_report() は、「my_default_custom_metric」という名前のアプリケーション コンテキストを作成します。

appd_custom_metric_report(nullptr, "Custom Metrics|my_default_custom_metric",some_value);
CODE

代替コンテキストの場合、appd_custom_metric_add() メソッドは代替アプリケーション コンテキストにカスタムメトリックを登録します。

appd_custom_metric_add(name, "Custom Metrics|my_second_custom_metric" , time_rollup_type, cluster_rollup_type, hole_handling_type);
CODE

または

appd_custom_metric_add("context2", "Custom Metrics|my_second_custom_metric" , time_rollup_type, cluster_rollup_type, hole_handling_type);
CODE

appd_custom_metric_report はデフォルトのアプリケーション コンテキストと、「my_second_custom_metric」という名前の代替アプリケーション コンテキストを作成します。

appd_custom_metric_report(name, "Custom Metrics|my_second_custom_metric",some_value);
CODE
appd_custom_metric_report("context2", "Custom Metrics|my_second_custom_metric",some_value);
CODE

コントローラでは、カスタムメトリックフォルダは、my_default_custom_metricmy_second_custom_metric の 2 つのエンティティを持つ「Custom Metrics」として、Metric Browser の関連付けられた階層の下に表示されます。

次の例は、両方のメソッドシグネチャを持つコールを示しています。

appd_custom_metric_add("app_context", "Custom Metrics|Memory|Total Memory Usage",
APPD_TIMEROLLUP_TYPE_AVERAGE, APPD_CLUSTERROLLUP_TYPE_INDIVIDUAL,
APPD_HOLEHANDLING_TYPE_RATE_COUNTER);
CODE

このメソッドは、アプリケーション コンテキスト(「Total Memory Usage」)とメトリックへのパス(Metric Browser の [Custom Metrics] > [Memory])をコントローラに渡します。その他のパラメータは、メトリックの処理方法を定義します。メトリックが宣言されると、次のようにコードで appd_custom_metric_report() メソッドを使用してメトリックにデータをレポートできます。

appd_custom_metric_report("app_context", "Custom Metrics|Memory|Total Memory Usage", 1234);
CODE

C++ アプリケーションのインストゥルメンテーションを簡素化するには、「C/C++ SDK リソース管理」を参照してください。 

メトリック処理パラメータ

コントローラでは、ビルトインメトリックと同様に、カスタムメトリック値にも一部の標準処理関数が適用されます。これらの関数では、メトリックが時間経過とともにロールオーバーされる方法などが定義できます。コントローラがカスタムメトリックを処理する方法は、メトリックの性質によって異なります。マシンの状態を表すメトリックの場合、コントローラはメトリックの最後に観測された値をキャプチャします。コール率メトリックの場合、コントローラは平均値を使用します。次のセクションでは、コントローラによるメトリック処理を定義するために使用できるパラメータについて説明します。

時間ロールアップタイプ

time_rollup_type パラメータは、メトリック値を時間経過とともにロールアップする方法をコントローラに指示します。コントローラでメトリックをロールアップする方法は、次の3つです。

  • 期間内にレポートされたすべての値の平均を計算できます。これを使用するビルトインメトリックの例は、Average Response Time メトリックです。
  • その1分以内にレポートされたすべての値の合計。この動作はカウンターと同様です。このメトリックの例は、Calls per Minute メトリックです。
  • 現在の値は、その1分以内に最後にレポートされた値です。その1分以内に値がレポートされない場合は、最後にレポートされた値が使用されます。これを使用するメトリックの例は、Max Available (MB) メトリックなどのマシン状態メトリックです。

クラスタロールアップタイプ

appd_cluster_rollup_type パラメータは、ティア(ノードのクラスタ)のメトリック値を集計する方法をコントローラに指示します。

  • Individual:ティア内の各ノードでのメトリック値を平均して、メトリック値を集計します。たとえば、Hardware Resources|Memory|Used % は個別ロールアップタイプを使用するビルトインメトリックです。
  • Collective:ティア内のすべてのノードのメトリック値を合計して、メトリック値を集計します。たとえば、Agent|Metric Upload|Metrics uploaded は集合ロールアップタイプを使用するビルトインメトリックです。 

ホール処理タイプ

特定のメトリックでは、特定の1分以内のデータがレポートされない場合があります。appd_hole_handling_type パラメータは、そのタイムスライスのメトリックカウントを設定する方法をコントローラに指示します。このカウントは、ホール処理タイプが REGULAR_COUNTER の場合は 0 に設定され、RATE_COUNTER の場合は 1 に設定されます。つまり、集計は REGULAR_COUNTER の影響を受けませんが、RATE_COUNTER の影響は受けます。 

たとえば、データ 9、3、0、12 を持つ 4 つのタイムスライスがあるとします。3 番目のタイムスライスには 0 が設定され、そのタイムスライスにはメトリックは報告されません。の合計は、9+3+0+12 = 24 です。

メトリックが REGULAR_COUNTER の場合、3 番目のタイムスライスのカウントは 0 なので、カウントの合計は 1+1+0+1 = 3 です。メトリックが RATE_COUNTER の場合、カウントの合計は 1+1+1+1 = 4 です。REGULAR_COUNTER の場合、平均値は 24/3 = 8、RATE_COUNTER の場合は 24/4 = 6 になります。 

通常のカウンタのホール処理タイプを使用するビルトインメトリックには、Average Response TimeAverage CPU UsedNumber of Stalls などがあります。レートカウンタのホール処理タイプを使用するビルトインメトリックには、BT Calls per minuteErrors per minute などがあります。 

コールグラフの生成

C/C++ SDKを使用して、コールグラフでレポートおよび表示されるようにメソッドをインストゥルメント化できます。次の方法のいずれかでメソッドをインストゥルメント化できます。

  • APPD_AUTO_FRAME マクロの使用(C++ のみ)
  • appd_frame_begin および appd_frame_end の使用

APPD_AUTO_FRAME マクロを使用したメソッドのインストゥルメント化

APPD_AUTO_FRAME マクロを使用して、C++ フレームワークでビルドされたアプリケーションをインストゥルメント化できます。このマクロは、appd_frame_begin および appd_frame_end メソッドを呼び出すことと同等です。

  1. コールをインストゥルメント化するビジネストランザクションを指定し、コールグラフのルートを構成します。

    appd::sdk::BT bt("mybt");
    APPD_AUTO_FRAME(bt);
    method1(bt);
    method2(bt);
    CODE

     

  2. 下記のとおりにメソッドをインストゥルメント化します。

    void method1(appd::sdk::BT& bt)
    {
     APPD_AUTO_FRAME(bt);
     // Code for method1...
    }
    void method2(appd::sdk::BT& bt)
    {
     APPD_AUTO_FRAME(bt);
     // Code for method2...
    }
    CODE

    メソッドにはビジネストランザクションへのアクセス権が必要であるため、ビジネストランザクションを引数としてメソッドに渡すことができます。

appd_frame_begin および appd_frame_end 関数を使用したメソッドのインストゥルメント化

C++以外のフレームワークでビルドされたアプリケーションのメソッドをインストゥルメント化できます。メソッドをインストゥルメント化するには、メソッドの開始時に appd_frame_begin を呼び出し、メソッドの終了時に appd_frame_end を呼び出します。これを実行すると、メソッド呼び出しの期間が自動的に計算され、コールグラフでレポートされます。 

メソッドで終了コールが行われると、appd_exitcall_beginappd_exitcall_end の間に終了コールコードを追加して終了コールをインストゥルメント化できます。

以下のコードのサンプルは、appd_frame_begin および appd_frame_end を使用してそれぞれインストゥルメント化され、ルートメソッド main() で呼び出される 3 つのメソッドを示しています。2 つ目のメソッドのサンプル method2() には、終了コールが含まれています。

void method1( )
{
 appd_frame_handle frameHandle = appd_frame_begin(btHandle, APPD_FRAME_TYPE_CPP, nullptr, APPD_FUNCTION_NAME, __FILE__, __LINE__);
 // code for method1
 appd_frame_end(btHandle, frameHandle);
}
CODE
void method2()
{
 appd_frame_handle frameHandle = appd_frame_begin(btHandle, APPD_FRAME_TYPE_CPP, nullptr, APPD_FUNCTION_NAME, __FILE__, __LINE__);
 // code for method2
appd_exitcall_handle exitCallHandle = appd_exitcall_begin(btHandle, BACKEND_NAME);
 // code for exit call
 appd_exitcall_end(exitCallHandle);
 appd_frame_end(btHandle, frameHandle);
}
CODE
void method3()
{
 // To illustrate instrumenting a method where this SDK cannot be used
 // method3 is a wrapper for the call of the actual method which will show up in the call graph
 appd_frame_handle frameHandle = appd_frame_begin(btHandle, APPD_FRAME_TYPE_CPP, "Test", "Compute", "C:\\modules\\source\\Test.cs", 143); 
 // call the wrapped method
 appd_frame_end(btHandle, frameHandle);
}
CODE


次の main() メソッドは、コールグラフのルートです。ここには、トランザクションを appd_bt_begin および appd_bt_end に渡すことで上記 3 つのメソッドを呼び出すビジネストランザクションが指定されます。

int main(int argc, char **argv)
{
 // initialize AppDynamics
 btHandle = appd_bt_begin(TRANSACTION_NAME, "");
 appd_frame_handle frameHandle = appd_frame_begin(btHandle, APPD_FRAME_TYPE_CPP, nullptr, APPD_FUNCTION_NAME, __FILE__, __LINE__);
 // code for main
 method1();
 method2();
 method3();
 appd_frame_end(btHandle, frameHandle);
 appd_bt_end(btHandle);
}
CODE

上記のメソッドのサンプルは、下記のコールグラフで表されています。

 Call Graph Methods

事前に入力されたコールグラフの生成(C++ のみ)

前のセクションでは、コード内でインストゥルメンテーション メソッドを呼び出すことによって、C/C++ アプリケーションをインストゥルメント化する方法について説明しました。ただし、ソースコードを変更できない場合は、ログファイルなどのソースのデータを使用して入力されたコールグラフを生成できます。

事前に入力されたコールグラフを生成するには、次の手順を実行します。

  1. コールグラフのルートを作成するには、CallGraph クラスをインスタンス化します。
    CallGraph クラスでは、次のパラメータを使用できます。

    • bt:ビジネストランザクション。

    • class_name:コールグラフのルートを含むクラスの名前。

    • method_name:コールグラフのルートを表すメソッドの名前。
    • file_path:クラスへのファイルパス。
    • line_number:メソッドの行番号。
    • time_msec:このフレーム(メソッド)が実行する時間(ミリ秒単位)
    • frame_type:フレームのタイプ(メソッドの言語)現在、APPD_FRAME_TYPE_CPP が唯一のオプションです。

    次の例は、CallGraph のインスタンス化を示しています。

    appd::sdk::CallGraph callGraph(bt, "Class1", "main", "/src/file1.cc", 276, 100, APPD_FRAME_TYPE_CPP);
    CODE


  2. 次に示すように、ルートおよび追加された任意の子で add_child を呼び出してコールグラフツリーを作成します。

    callGraph.root() .add_child("Class2", "method1", "/src/file2.cc"), 101, 40, APPD_FRAME_TYPE_CPP) .add_child("Class2", "method2", "/src/file2.cc"), 523, 30, APPD_FRAME_TYPE_CPP); auto& cge1 = callGraph.root() .add_child("Class3", "method1", "/src/file3.cc"), 27, 30, APPD_FRAME_TYPE_CPP); cge1.add_child("Class3", "method2", "/src/file3.cc"), 430, 15, APPD_FRAME_TYPE_CPP);
    CODE
  3. コールグラフで add_to_snapshot を呼び出します。これが機能するには、ビジネストランザクションがスナップショットを取得する必要があります。

    callGraph.add_to_snapshot(); 
    CODE

Analytics での C++ SDK サポート

以前はデータをスナップショットに追加するためだけに使用されていた既存の API メソッドのうち 2 つは、コントローラ上の現在のビジネストランザクションに対して分析が有効になっている場合、分析データを送信するようになりました。

  • スナップショットに URL を設定:スナップショットを取得している場合は、URL が設定されます。データは 7 ビット ASCII または UTF-8 である必要があります。スナップショットを取得しない場合も、この関数を呼び出せます。指定のビジネストランザクションでスナップショットが取得されていないときは、この関数がすぐに戻ります。ただし、この関数に渡すデータの抽出はコストが高い場合、appd_bt_is_snapshotting を使用して、データが抽出され、この関数が呼び出される前にビジネストランザクションでスナップショットが取得されているかどうかを確認できます。

    void appd_bt_set_url(appd_bt_handle bt, const char* url);
    CODE
    • param bt:ユーザデータを追加するビジネストランザクション(スナップショットを取得している場合)。
    • param url:7 ビット ASCII または UTF-8 として取得されるスナップショットの URL 値。
  • ユーザデータをスナップショットに追加:データは 7 ビット ASCII または UTF-8 である必要があります。スナップショットが取得されていない、または分析が有効になっていない場合も、この関数を呼び出せます。このデータはスナップショット専用であり、この関数に渡すデータの抽出はコストが高い場合は、appd_bt_is_snapshotting を使用して、データを抽出してこの関数を呼び出す前にビジネストランザクションでスナップショットが取得されているかどうかを確認できます。

    void appd_bt_add_user_data(appd_bt_handle bt, const char* key, const char* value);
    CODE


    • param bt:ユーザデータを追加するビジネストランザクション(スナップショットを取得している場合)。
    • param key:7 ビット ASCII または UTF-8 としてスナップショットに追加するユーザデータの名前。
    • param value:7 ビット ASCII または UTF-8 としてスナップショットに追加するユーザデータの値。

これらの API メソッドはすでに存在しましたが、分析へのデータの報告はできませんでした。分析に正常に接続するには、次の構成 API を使用して初期化します。

void appd_config_set_analytics_host(struct appd_config* cfg, const char* host); 
CODE
  • param host:分析エージェントのホスト(デフォルトは localhost)。
void appd_config_set_analytics_port(struct appd_config* cfg, const unsigned short port);
CODE
  • param port:分析エージェントが待機しているポート(デフォルトは 9090)。

エージェントの終了

アプリケーションが終了する直前に SDK を終了します。

appd_sdk_term();
CPP