Android SDK を使用して Android アプリケーションをインストゥルメント化すると、SDK によって公開される API を使用して、コントローラ UI に表示されるアプリケーションのデータをカスタマイズすることもできます。以下のセクションでは、Android API を使用してインストゥルメンテーションをカスタマイズする方法について説明します。

Android エージェントは情報を報告する前にローカルバッファにイベントに関するデータを保存するため、注意して API を使用することをお勧めします。

データの追加タイプの収集

Instrumentation クラスには、モバイル RUM を使用して収集および集約できるアプリケーションデータの種類を拡張できる追加のメソッドがあります。作成できる拡張には、次の 6 つの基本タイプがあります。

内線番号

説明

仕様

コントローラ UI でデータが表示される場所

情報ポイントメソッドが呼び出される頻度と実行される時間
  • データは数値
  • 名前には、
    英数字とスペースを使用
カスタムタイマーコード内の任意のイベントシーケンスが、
複数のメソッドにまたがる場合でも、時間を計測
  • データは数値
  • メトリック名には、
    英数字とスペースを使用
カスタムメトリック収集する整数ベースのデータ
  • データは数値
  • メトリック名には、
    英数字とスペースを使用
ユーザデータ有用と思われる任意の文字列キーと値のペア
  • 任意のデータ型
  • メトリック名には制限なし
トピックパス(パンくずリスト)クラッシュのコンテキスト
  • 任意のデータ型
  • メトリック名には制限なし
ユーザインタラクションユーザがボタンを押したとき、リストをクリックしたとき、およびテキストを選択したときにキャプチャ
  • 任意のデータ型
  • メトリック名には制限なし

情報ポイント、カスタムタイマー、カスタムメトリック、ユーザデータを設定した場合、モバイルエージェントはモバイルビーコンでそのデータをパッケージ化します。通常、ビーコンは、インストゥルメント化されたアプリケーションが HTTP リクエストを送信したとき、またはクラッシュ後にアプリケーションが起動したときに、送信されますが、カスタムデータが収集済みで、これらのイベントが少なくとも 5 分間発生しなかった場合、カスタムデータはその時点で送信されます。

情報ポイント

情報ポイントを使用すると、独自のコードがどのように実行されているかを追跡できます。メソッドが呼び出される頻度、実行にかかる時間、および例外がスローされたかどうかを確認できます。情報ポイントを設定する最も簡単な方法は、@InfoPoint 注釈を使用することです。例:

@InfoPoint
 public void infoPointMethod(String arg1, int arg2, long value) {
   System.out.println("Executing infoPointMethod!");
 }
JAVA

CallTracker インターフェイスを使用して手動で実行することもできます。たとえば、downloadImage メソッドに関する情報を収集するには、次のようなコードを使用できます。

private void downloadImage(URL url) {
     CallTracker tracker =
          Instrumentation.beginCall("com.example.android.awesomeapp.ImageDownloader", "downloadImage")
              .withArguments(url);
     try {
          //download image.
          tracker.reportCallEnded()
     } catch(Exception e) {
         //handle exception thrown
         tracker.reportCallEndedWithException(e);
     }
 }
JAVA

この情報は、コントローラ UI の [Custom Data] ビューに表示されます。

カスタムタイマー

カスタムタイマーでは、startTimerstopTimer を使用して、複数のメソッドにまたがる場合でも、コード内の任意のイベントシーケンスの時間を測定できます。

public class MyActivity extends Activity {
   @Override
   protected void onStart(){
       Instrumentation.startTimer("Time Spent on MyActivity");
       //your code here.
   }
 
   @Override
   protected void onStop(){
       Instrumentation.stopTimer("Time Spent on MyActivity");
       //your code here.
   }
 }
JAVA

メソッド startTimer(String) および stopTime(String) はさまざまなスレッドから呼び出すことができます。同じ名前値を使用して startTimer を再度呼び出すと、名前付きタイマーがリセットされます。

この情報は、コントローラ UI の [Custom Data] ビューに表示されます。

Custom Metrics

任意の整数ベースのデータを Android エージェントに渡すことができます。reportMetric コールの最初のパラメータは、メトリックをコントローラ UI に表示する場合の名前です。メトリック名には、英数字とスペースのみを使用します。不正な文字は、ASCII 16 進値に置き換えられます。

たとえば、ユーザが UI のチェックアウトボタンをクリックした回数を追跡するには、次のようなコードを使用できます。

findViewById(R.id.checkout_button).setOnClickListener(new View.OnClickListener(){
      @Override
      public void onClick(View view){
          //run your checkout routine.
          Instrumentation.reportMetric("Checkout Count", 1);
      }
 });
JAVA

この情報は、コントローラ UI の [Custom Data] ビューに表示されます。

Custom User Data

次のメソッドで役立つ任意の文字列キー/値のペアを設定し、後で削除することができます。

  • setUserData(key, value, success, error)

パラメータ

次の表で、パラメータについて説明します。

名前タイプ説明
キーstringキーと値のペアを識別するキー。
stringキーに関連付けられている値。
successfunctionユーザ定義のコールバックの成功例。
errorfunctionユーザ定義のコールバックの失敗例。


次のコード例は、SDK API を使用してユーザーデータを設定する方法を示しています。

void onUserLoggedIn(String userid) {
    Instrumentation.setUserData("User ID", userid);
    ...
}
JAVA

次のコード例は、SDK API を使用してユーザーデータを削除する方法を示しています。

void onUserLoggedIn(String userid) {
    Instrumentation.removeUserData("User ID", userid);
    ...
}
JAVA

この情報は、[Network Request Analyze] で確認でき、クラッシュスナップショットに追加されます。キーと値はそれぞれ 2048 文字に制限されています。

また、次のメソッドを使用して、他のデータ型(Long、Boolean、Double、Date)の値を含むユーザデータを設定することもできます。


トピックパス(パンくずリスト)

トピックパスを使用すると、ユーザエクスペリエンスのコンテキストでクラッシュの場所を特定できます。一連のイベントをキャプチャする場合は、トピックパスを設定します。その後のある時点でアプリケーションがクラッシュした場合、トピックパスはクラッシュレポートとともに表示されます。

トピックパスを残すには、次の 2 つの方法があります。

  • クラッシュレポートのみ
  • モーダル

クラッシュレポートのみ

次のメソッドを使用すると、トピックパスがクラッシュレポートのみで報告されます。

public static void leaveBreadcrumb(java.lang.String breadcrumb)
JAVA

モーダル

次のメソッドを使用すると、トピックパスが報告される場所を微調整(クラッシュレポートのみ、またはクラッシュレポートとセッションを選択)できます。

public static void leaveBreadcrumb(java.lang.String breadcrumb, int mode)
JAVA

ここで、modeは次のいずれかです。

  • CRASHES_ONLY
  • CRASHES_AND_SESSIONS

breadcrumb が 2048 文字を超えている場合は、切り捨てられます。空の場合、トピックパスは記録されません。各クラッシュレポートには、最近の 99 件のトピックパスが表示されます。

クラッシュ レポート コールバックの追加

コードの他の部分(Google アナリティクスなど)が Android エージェントにより収集されるクラッシュレポート情報を使用できるようにすることがあります。サマリークラッシュ情報を渡すことができるようにするには、クラッシュレポートのランタイムコールバックを設定します。Android エージェントがクラッシュを検出して報告するときに、コールバックを取得するには、コードに次のインターフェイスを実装します。

public interface CrashReportCallback {
    void onCrashesReported(Collection<CrashReportSummary> summaries);
}
JAVA

Android エージェントは、複数のクラッシュがあり、複数のクラッシュレポート概要が生成される場合、個々のコールバックではなく、一連のクラッシュレポート概要を送信します。

メソッド onCrashesReported は、クラッシュ発生後の Android エージェントの次の初期化中に呼び出されます。

このコールバックはアプリケーションの UI スレッドで呼び出されるため、作業は別の作業スレッドで実行する必要があります。

CrashReportSummary に次のプロパティがあります。

public class CrashReportSummary {
    public final String crashId;
    public final String exceptionClass;
    public final String exceptionMessage;
}
JAVA


Google アナリティクスなどの別の分析ツールに情報を送信する場合は、3 つのプロパティすべてを含めることをお勧めします。exceptionClass および exceptionMessage は、クラッシュを迅速に識別するのに役立ち、crashId はコントローラ UI でクラッシュを検索する際に役立ちます。

たとえば、クラッシュ情報を Android のロガーに出力するには、次の CrashReportCallback クラスを実装できます。

public static class MyCrashReportCallback implements CrashReportCallback {
    @Override
    public void onCrashesReported(Collection<CrashReportSummary> summaries) {
        for (CrashReportSummary crash : summaries) {
            Log.e("MyApp", "Crash Detected: " + crash.exceptionClass + " : " + crash.exceptionMessage + " (" + crash.crashId + ")");
        }
    }
}
JAVA

AgentConfiguration オブジェクトを使用してコールバックを設定します。

final AgentConfiguration config = AgentConfiguration.builder()
        .withAppKey(appKey)
        .withContext(context)
        .withCrashCallback(new MyCrashReportCallback())
        .build();
JAVA

コールバックは、メインスレッドで、クラッシュ後の次の初期化中に呼び出されます。詳細については、Android SDK API最新の Java ドキュメントを参照してください。

クラッシュレポートの無効化

クラッシュレポートはデフォルトで有効になっていますが、インストゥルメンテーション構成を使用して手動でクラッシュレポートを無効にできます。他のクラッシュレポートツールを使用している場合、競合を最小限に抑え、クラッシュレポートの結果を最適化するために、クラッシュレポートを無効にする場合があります。 

次に示すように、crashReportingEnabled プロパティを使用してインストゥルメンテーションを構成することにより、クラッシュレポートを無効にできます。

let config = ADEumAgentConfiguration(appKey: <#EUM_APP_KEY#>);
config.crashReportingEnabled = false;
ADEumInstrumentation.initWith(config);
JAVA

エラーと例外のレポート

reportError に使用される新しい throwable の構成に使用される文字列メッセージでは、ハッシュ、StackTraceID、または ThreadID などの一意の文字列を使用しないでください。これらを含めると、Error Group が無数に作成され、パフォーマンスに影響を与えます。

一意のエラー文字列と値を追加するには、次の 2 つのデータ収集オプションがあります。

  • トピックパスとして文字列値を追加します。報告するイベント/エラーに単一の値が添付されている場合は、その値を leaveBreadcrumb に追加します。「トピックパス(パンくずリスト)」を参照してください
  • 文字列名と整数値を追加します。報告するイベント/エラーに名前と整数値の両方が添付されている場合は、その値を reportMetric に追加します。「カスタムメトリック」を参照してください。


Instrumentation クラスの reportError メソッドを使用して例外を報告できます。報告された例外は、セッション詳細に表示されます。

また、問題に対して次のシビラティ(重大度)レベルの 1 つを設定することもできます。シビラティ(重大度)レベルを使用すると、[Code Issues Dashboard] または [Code Issues Analyze] でエラーをフィルタリングできます。

  • ErrorSeverityLevel.INFO
  • ErrorSeverityLevel.WARNING
  • ErrorSeverityLevel.CRITICAL

次の例では、API を使用して考えられる例外を報告し、ファイルへの書き込み時にシビラティ(重大度)レベルを ErrorSeverityLevel.CRITICAL(クリティカル)に設定します。

private void writeToFile(String filePath, String data) {
    try {
        OutputStream outputStream = new FileOutputStream(filePath);
        Writer outputStreamWriter = new OutputStreamWriter(outputStream);
        outputStreamWriter.write(data);
        outputStreamWriter.close();
    } catch (IOException e) {
        Log.e("Exception", "File write failed: " + e.toString());
        Instrumentation.reportError(e, ErrorSeverityLevel.CRITICAL);
    }
}
JAVA


コレクタへのユーザデータの送信を停止する場合のエージェントの無効化

エージェントの初期化中および実行中に、エージェントを無効にしてコレクタへのすべてのデータの送信を停止できます。たとえば、プライバシー上の理由でユーザがモニタリングをオプトアウトするオプションがアプリにある場合は、エージェントを無効にできます。

shutdownAgent

shutdownAgent  コールはコレクタへの発信データを停止し、デバイスにデータを保持しません。

Instrumentation.shutdownAgent();
JAVA
  • このコールは、エージェントからのトラフィックのみを停止します。
  • エージェントが初期化されると、コールは削除できず、ライセンスが消費されます。
  • この状態をデバイスで永続的にする場合は、UserDefaults にコードを追加して状態を保存し、そのフラグを使用してコード内のエージェントを条件付きで初期化します。

restartAgent

エージェントを再度有効にして shutdownAgent を無効にする場合は、restartAgent を使用します。

Instrumentation.restartAgent();
JAVA
  • このコールは、同様にリモートでエージェントをシャットダウンできるサーバ側のコールにも対応します。 
  • コールは、アプリケーションの実行中にのみ有効です。
  • エージェントがリモートで無効になっている場合、コールは無視されます。
  • コールがメモリから削除され、アプリケーションが再起動されるか、デバイスが再起動されると、エージェントは通常どおり初期化されます。 

ハイブリッドサポートの設定

デフォルトでは、Android エージェントは JavaScript エージェントを Android WebView に挿入して、インストゥルメント化します。この機能の概要と説明については、「ハイブリッド アプリケーションのサポート」を参照してください。 

ハイブリッドサポートのランタイム設定

次のコード例では、JavaScript エージェントのインジェクションを無効にしています。クライアントがこのフラグに false を受け取ると、JavaScript エージェントは無効になります。そのため、WebViews はインストゥルメント化されず、Ajax 要求は監視されません。

Instrumentation.start(
    AgentConfiguration.builder()
        .withAppKey(getString(R.string.app_key))
        .withContext(applicationContext)
        .withJSAgentInjectionEnabled(false)
        .build())
JAVA

インジェクションは、新しい WKWebView の作成時に発生します。このため、このフラグが false に設定されているときに WKWebView が作成された場合、その特定の WKWebView は、その後フラグが true に設定されてもインストゥルメント化されません

Ajax コールの収集およびレポートは、デフォルトでは無効になっています。Ajax コールのインジェクションおよび収集とレポートを有効にするには、次に示すようにインストゥルメンテーションの構成でメソッド jsAgentEnabledtrue を渡します。

Instrumentation.start(
    AgentConfiguration.builder()
    .withAppKey(getString(R.string.app_key))
    .withContext(applicationContext)
    .withJSAgentAjaxEnabled(true)
    .build())
JAVA

プログラムによるセッションの制御

デフォルトでは、ユーザが非アクティブになってからモバイルセッションが終了します。たとえば、ユーザがアプリケーションを開くと、セッションは開始され、ユーザが設定した期間にアプリケーションを使用しなくなった後にのみ終了します。ユーザがアプリケーションの再使用を開始すると、新しいセッションが開始されます。 

ただし、セッションの期間を定義するのに非アクティブな期間を設定する代わりに、次の API を使用して、セッションの開始と終了をプログラムで制御できます。

void startNextSession()
JAVA

インストゥルメンテーション クラスからメソッド startNextSession を呼び出すと、現在のセッションが終了し、新しいセッションが開始されます。API を使用すると、セッションを定義してフレーム化することができます。これにより、ビジネス目標と予想されるユーザフローをより厳密に合わせることができます。たとえば、API を使用して、製品の購入を追跡するセッションを定義したり、新しいユーザを登録したりすることができます。 

この API を過剰に使用すると、セッションが調整されます(過剰使用は Android エージェントごとに 1 分あたり 10 コールを超えた場合になりますが、変更される可能性があります)。API を使用しない場合、セッションは、ユーザが非アクティブになった後、デフォルトの終了にフォールバックします。

プログラムによって制御されるセッションの例

次のコード例では、現在のセッションが終了し、チェックアウトが行われると新しいセッションが開始されます。

public void checkoutCart(){
    if (currentCartItems!=null && currentCartItems.size()>0){
        CheckoutTask checkoutReq = new CheckoutTask();
        checkoutReq.execute(getEndpoint() + "cart/co");
        currentCartItemsMap.clear();
        convertItemsMaptoList();
        Instrumentation.startNextSession();
    } else {
        displayToast("There are no items in the cart");
    }
}
JAVA

セッションフレームの開始と終了

SessionFrame API を使用して、セッションアクティビティに表示されるセッションフレームを作成できます。セッションフレームは、セッション中にユーザが実行している内容のコンテキストを提供します。この API を使用すると、ユーザ画面の命名方法が向上し、ビジネスコンテキスト内のユーザフローを記録できます。 

使用例

次に、SessionFrame API の一般的な使用例を示します。

  • 1 つのアクティビティが複数の機能を実行し、個々の機能をより詳細に追跡します。
  • ユーザフローは、複数のアクティビティまたはユーザのインタラクションに及びます。たとえば、API を使用してセッションフレーム「Login」、「Product Selection」、および「Purchase」を作成して、ユーザが購入のためにフローを記録することができます。
  • ユーザの操作に基づいて動的情報をキャプチャし、オーダー ID などのセッションフレームに名前を付けることができます。

SessionFrame API

次の表に、セッションフレームで使用できる 3 つのメソッドを示します。

クラス

メソッド

[説明(Description)]

Instrumentation
static SessionFrame startSessionFrame(String sessionFrameName)
JAVA

セッションフレームを開始して名前を付けるには、これを使用します。

セッションフレームをネーミングすると、のフレームを簡単に識別して追跡できます。Sessions Dialog.

SessionFrame
static void updateName(String updatedSessionFrameName)
JAVA

セッションフレームを開始して名前を付けるには、これを使用します。

セッションフレームをネーミングすると、のフレームを簡単に識別して追跡できます。Sessions Dialog.

SessionFrame
static void end()
JAVA
セッションフレームを終了します。startSessionFrame から返された SessionFrame オブジェクトからこのメソッドを呼び出すことができます。

セッションフレームの例

次の例では、ShoppingCartActivity クラスが SessionFrame API を使用し、チェックアウトプロセス中にユーザアクティビティをトラッキングします。 

public class ShoppingCartActivity extends Activity {
 
  SessionFrame checkoutSessionFrame;
 
  public void onCheckoutCartButtonClicked() {
    // The user starts the checkout by clicking the checkout button.
    // This may be after they have updated the quantities of items in the cart, etc.
    checkoutSessionFrame = Instrumentation.startSessionFrame("Checkout");
  }
 
  public void onConfirmOrderButtonClicked() {
    // Once they have confirmed payment info and shipping information, and they
    // are clicking the "Confirm" button to start the backend process of checking out,
    // we may know more information about the order itself, such as an order ID.
    checkoutSessionFrame.updateName("Checkout: Order ID " + orderId);
  }
 
  public void onProcessOrderCompleted() {
    // Once the order is processed, the user is done "checking out", so we end the session frame.
    checkoutSessionFrame.end();
    checkoutSessionFrame = null;
  }
 
  public void onCheckoutCanceled() {
    // If the user cancels or returns to the cart, you'll want to end the session frame also, or else it will be
    // left open and appear to have never ended.
    checkoutSessionFrame.end();
    checkoutSessionFrame = null;
  }
}
JAVA

カスタム HTTP ライブラリの使用

基盤となる実装がサポートされているいずれかのネットワークライブラリによって処理されると、Android エージェントは自動的にネットワーク要求を検出します。Android エージェントがカスタムライブラリからの要求を検出するようにするには、HttpRequestTracker インターフェイスを使用してアプリケーションに手動で要求トラッキングコードを追加します。  

サポート対象のネットワークライブラリ

以下のライブラリは、Android ネットワーク要求の大部分をカバーしています。ただし、モバイルアプリケーションでは、カスタム HTTP ライブラリが使用される場合があります。  

  • HttpURLConnection
  • HttpsURLConnection
  • HttpClientクラス
  • OkHttp
  • OkHttp3
  • ch.boye.httpclientandroidlib

サーバ側の処理との相関を許可するようにヘッダーを設定するには、ServerCorrelationHeaders クラスを使用します。  

リクエストトラッキングの追加

リクエストトラッキングを手動で追加するには、HttpRequestTracker オブジェクトを使用し、エージェントにリクエストの開始時と終了時を通知し、応答のフィールドをエージェントに報告します。

要求のトラッキング

HTTP 要求の追跡を開始するには、次のインターフェイスのインスタンスを使用します。

このインターフェイスを使用する前に、Instrumentation.start メソッドを使用してエージェントを初期化する必要があります。

public interface HttpRequestTracker {
    public Exception getException();
    public HttpRequestTracker withException(Exception e);
  
    public String getError();
    public HttpRequestTracker withError(String error);
  
    public int getResponseCode();
    public HttpRequestTracker withResponseCode(int responseCode);
  
    public Map<String, List<String>> getResponseHeaderFields();
    public HttpRequestTracker withResponseHeaderFields(Map<String, List<String>> responseHeaderFields);
  
   /**
    * Stops tracking an HTTP request.
    *
    * Immediately after receiving a response or an error, set the appropriate fields and call this method to
    * report the outcome of the HTTP request. You should not continue to use this object after calling this
    * method -- if you need to track another request, obtain a new instance.
    */
    public void reportDone();
}
JAVA

次のようなリクエストスニペットがあるとします。

public byte[] sendRequest(URL url) throws HttpException {
    try {
        // implementation omitted
        return responseBody;
    } catch (UnderlyingException e) {
        throw new HttpException(e);
    }
}
JAVA


トラッカーを追加すると、次のようになります。

public byte[] sendRequest(URL url) throws HttpException {
    HttpRequestTracker tracker = Instrumentation.beginHttpRequest(url);
    try {
        // implementation omitted
        tracker.withResponseCode(theResponseCode)
               .withResponseHeaderFields(theResponseHeaderFields)
               .reportDone();
        return responseBody;
    } catch (UnderlyingException e) {
        tracker.withException(e)
               .reportDone();
        throw new HttpException(e);
    }
}
JAVA

ネットワークリクエストへのカスタム ユーザ データ プロパティの追加

HttpRequestTracker にユーザデータを追加することで、特定のネットワークリクエストにカスタム ユーザ データ プロパティを追加できます。

public HttpRequestTracker withUserData(String key, String value)
public HttpRequestTracker withUserLong(String key, Long value)
public HttpRequestTracker withUserBoolean(String key, Boolean value)
public HttpRequestTracker withUserDouble(String key, Double value)
public HttpRequestTracker withUserDate(String key, Date value)
JAVA

public byte[] sendRequest(URL url) throws HttpException {
    HttpRequestTracker tracker = Instrumentation.beginHttpRequest(url);
    try {
        // implementation omitted
        tracker.withResponseCode(theResponseCode)
               .withResponseHeaderFields(theResponseHeaderFields)
               .withUserData("key", "value")
               .withUserLong("number", 100)
               .withUserBoolean("boolean", true)
               .withUserDouble("double", 1.1234)
               .withUserDate("date", 1609488000)
               .reportDone();
        return responseBody;
    } catch (UnderlyingException e) {
        tracker.withException(e)
               .reportDone();
        throw new HttpException(e);
    }
}
JAVA

サーバ側の相関を有効にする

要求とサーバ側の処理の相関を有効にするには、サーバ側のエージェントが検出できる発信要求に特定のヘッダーを追加します。

これは、標準 HTTP ライブラリに対して自動的に実行されます。

public class ServerCorrelationHeaders {
    public static Map<String, List<String>> generate();
}
JAVA


次の作業が必要です。

  1. バックエンドにリクエストを送信する前に、generate メソッドを呼び出し、生成されたヘッダーを設定します。
  2. withResponseHeaderFields フィールドのデータを使用して、応答ヘッダーを報告します。

要求/応答のコンテンツ長をオーバーライドする

  • 通常は、HttpRequestTracker.withRequestHeaderFields()HttpRequestTracker.withResponseHeaderFields() を使用してヘッダーを渡すことで、ネットワーク要求と応答のコンテンツ長を取得できます。
  • 何らかの理由でこれがカスタム HTTP トラッキングに対して機能しない場合(つまり、ネットワークライブラリが送信されるまでこれらのフィールドにデータを入力しない場合)でも、HttpRequestTracker.withRequestContentLength(Long length) および HttpRequestTracker.withResponseContentLength(Long length) を使用して要求と応答のコンテンツの長さを報告できます。

  • たとえば、コンテンツが byte 配列の要求をトラッキングするとします。次のように、バイト配列のサイズを渡すことで、要求のコンテンツの長さを報告できます。

byte[] requestContent;
HttpRequestTracker tracker;
tracker.withRequestContentLength(requestContent.size());
JAVA

エージェント設定のカスタマイズ

エージェント自体の動作をカスタマイズするには、AgentConfiguration オブジェクトを Instrumentation.start メソッドに渡します。AgentConfiguration オブジェクトを使用すると、次のことができます。

  • オンプレミス EUM サーバをポイントする
  • ロギングを有効にする
  • アプリケーション名をカスタム設定する。これは、異なるパッケージ名を持つ同じアプリケーションバイナリを異なる地理的領域に展開する場合に便利です。これにより、すべてのデータが同じ名前で処理されるようになります。
  • ネットワーク要求に使用されていないアプリケーション内部の HTTP 要求を無視する
  • カスタム HTTP ライブラリを使用してビーコンを送信するようにエージェントを設定する

構文

詳細については、最新の Java ドキュメントを参照してください。

Instrumentation.start(AgentConfiguration.builder()
      .withAppKey("<EUM_APP_KEY>")
      .withContext(getApplicationContext())
      .withCollectorURL(collectorURL*) // The URL of the EUM Server(on-prem)
      .withCompileTimeInstrumentationCheck(true) // Set to false if you are using features of the SDK only, like custom HTTP support, but not to instrument your app.      
      .withLoggingEnabled(true)//set default INFO logging. Tagged "AppDynamics".
      .withApplicationName(applicationName)//set a custom app name
      .withExcludedUrlPatterns(excludedUrlPatterns) // Set excluded url regex patterns for http tracking
      .withCollectorChannelFactory(collectorChannelFactory()) // The custom HTTP implementation to use
      .build());
JAVA

*EUM サーバの URL のリストについては、「Cisco AppDynamics SaaS Domains and IP Ranges」を参照してください。

カスタム HTTP ライブラリを使用するようにエージェントを設定する

Android エージェントは、ビーコンを配信するために HTTP を使用します。エージェントがカスタム HTTP ライブラリを使用してビーコンを配信する場合は、次の手順を実行します。

  1. 次の抽象クラスを拡張するクラスを実装します。

    public abstract class CollectorChannel {
        private URL url;
        private int connectTimeout;
        private int readTimeout;
        private Map<String, List<String>> requestProperties = new HashMap<String, List<String>>();
        private String requestMethod;
      
        public void setURL(URL url) {
            this.url = url;
        }
      
        public URL getURL() {
            return url;
        }
      
        public void setConnectTimeout(int connectTimeout) {
            this.connectTimeout = connectTimeout;
        }
      
        public int getConnectTimeout() {
            return connectTimeout;
        }
      
        public void setReadTimeout(int readTimeout) {
            this.readTimeout = readTimeout;
        }
      
        public int getReadTimeout() {
            return readTimeout;
        }
      
        public void addRequestProperty(String property, String value) {
            if (!requestProperties.containsKey(property)) {
                requestProperties.put(property, new ArrayList<String>());
            }
            requestProperties.get(property).add(value);
        }
      
        public Map<String, List<String>> getRequestProperties() {
            return Collections.unmodifiableMap(requestProperties);
        }
      
        public void setRequestMethod(String requestMethod) {
            this.requestMethod = requestMethod;
        }
      
        public String getRequestMethod() {
            return requestMethod;
        }
      
        public abstract OutputStream getOutputStream() throws IOException;
      
        public abstract InputStream getInputStream() throws IOException;
      
        public abstract int getResponseCode() throws IOException;
      
        public abstract Map<String,List<String>> getHeaderFields() throws IOException;
    }
    JAVA


    このインターフェイスは、おおむね HttpURLConnection に基づいています。

  2. CollectorChannelFactory インターフェイスのバージョンを実装します。

    public interface CollectorChannelFactory {
     
        /**
         * Returns a new instance of CollectorChannel.
         *
         * If you want to supply a custom CollectorChannel, implement this interface, and return
         * an instance of your concrete implementation of CollectorChannel from this method.
         */
        public CollectorChannel newCollectorChannel();
    }
    JAVA

    newCollectorChannel の実装は、CollectorChannel の実装の新しいインスタンスを返す必要があります。

  3. CollectorChannelFactoryAgentConfiguration オブジェクトに渡します。

ユーザインタラクションのキャプチャ

特定のユーザインタラクションをトラッキングするように、エージェントを有効化できます。ユーザインタラクションがキャプチャされると、UI イベントごとにセッションをソートし、セッション ウォーターフォールのタイムラインで UI イベントを表示することができます。 

ユーザが次のいずれかまたはすべてを実行するときにキャプチャできます。

  • ボタンのクリック
  • テキストフィールドの選択
  • リスト項目のクリック

セキュリティおよびプライバシー上の懸念点

インタラクション キャプチャ モードは、セキュリティとプライバシー上の理由でデフォルトでは無効になっています。これは、ユーザインタラクションに機密情報が含まれている可能性があるためです。UI インタラクションとスクリーンショットのキャプチャの両方を有効にすると、このような潜在的なセキュリティとプライバシー上の問題が複合化する場合があります。 

ユーザ インタラクション キャプチャ モードの有効化

ユーザインタラクションのキャプチャモードを有効にするには、AgentConfigurationオブジェクトからメソッド withInteractionCaptureMode() にキャプチャモードを渡します。次のインストゥルメンテーション コードの例では、サポート対象のすべてのタイプのユーザインタラクションをキャプチャするように Android エージェントを設定します。

Instrumentation.start(AgentConfiguration.builder()
      .withAppKey("<EUM_APP_KEY>")
      .withContext(getApplicationContext())
      .withInteractionCaptureMode(InteractionCaptureMode.All)
      .build());
JAVA


また、1 つのタイプのユーザインタラクションのみをキャプチャするように Android エージェントを設定することもできます。

Instrumentation.start(AgentConfiguration.builder()
      .withAppKey("<EUM_APP_KEY>")
      .withContext(getApplicationContext())
      .withInteractionCaptureMode(InteractionCaptureMode.ButtonPressed)
      .build());
JAVA

プログラムによるスクリーンショットの取得

デフォルトでは、モバイルスクリーンショットはエージェント側で有効になりますが、コントローラ側では無効になります。プログラムで手動でスクリーンショットを取得するには、コントローラ UI でスクリーンショットを有効にし、次の API を追加する必要があります。

Instrumentation.takeScreenshot();
JAVA


たとえば、UI 要素をロードして、この要素がユーザにどのように表示されるかを確認した後に、スクリーンショットを取得できます。

@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_spinner_with_toast);
   spinner = (Spinner) findViewById(R.id.spnOptions);
   btnSpinnerVal = (Button) findViewById(R.id.btnSpinnerValue);
   loadSpinner();
   Instrumentation.takeScreenshot();
}
JAVA


スクリーンショットの無効化

コントローラ UI からまたは Android SDK を使用すると、スクリーンショットを無効にすることができます。Android SDK を使用してスクリーンショットを無効にするには、AgentConfiguration クラスからメソッド withScreenshotsEnabled(false) を使用します。

Instrumentation.start(AgentConfiguration.builder()
     .withAppKey("<EUM_APP_KEY>")
     .withContext(getApplicationContext())
     .withScreenshotsEnabled(false)
     .build());
}
JAVA

スクリーンショットのブロック/ブロック解除

Android SDK を使用すると、コードブロックの実行中にスクリーンショットが実行されないようにブロックすることもできます。これにより、スクリーンショットのブロックを解除するまで、スクリーンショットの作成が一時的にブロックされます。これにより、ユーザがログインやアカウント画面などで個人データを入力する状況でのスクリーンショットの作成を停止できます。

Instrumentation.blockScreenshots()Instrumentation.unblockScreenshots() のメソッドを使用して、スクリーンショットをブロックおよびブロック解除します。スクリーンショットが AgentConfiguration.Builder.withScreenshotsEnabled(true) またはコントローラの UI を使用して無効になっている場合、これらのメソッドは効果がありません。スクリーンショットがブロックされているかどうかを確認するために Instrumentation.screenshotsBlocked() を呼び出すことができます。

次の例は、ユーザ情報を表示するときに API を使用してスクリーンショットをブロックおよびブロック解除する方法を示しています。

public class UserAccountActivity extends Activity {
  ...
  public void displayCustomerAccount() {
    // Check to see if screenshots are blocked
    if (! Instrumentation.screenshotsBlocked()) {
        // If screenshots aren't blocked, block them before showing customer details
        Instrumentation.blockScreenshots();   
    }
    // Code to display customer details
    displayAccount(this.user);
    // After you're done, unblock screenshots
    Instrumentation.unblockScreenshots();
  }
  ...
}
JAVA


ネットワークリクエストに対応した URL の変換

アプリケーションがネットワークリクエストを行う場合、機密情報が含まれている URL を EUM サーバに報告したくない場合があります。その場合は、ネットワークリクエスト URL を報告する前に変換するか、すべて無視します。

  1. 特定の URL を変更または無視するネットワーク リクエスト コールバックを実装します。 
  2. 初期化コードにネットワーク リクエスト コールバックを登録します。

ネットワーク要求のコールバックの実装

特定の URL を変更または無視するコールバックは、次のインターフェイスの実装です。メソッド onNetworkRequest は同期されているため、関数からすばやく戻ることをお勧めします。

public interface com.appdynamics.eumagent.runtime.NetworkRequestCallback  {
    boolean onNetworkRequest(HttpRequestTracker httpRequestTracker);
}
JAVA

URL の変換

通常 、onNetworkRequest メソッドは次の手順に従って URL を変換する必要があります。

  1. 正規表現やパターンマッチングなどの手法を使用して、特定の URL を識別します。
  2. HttpRequestTracker オブジェクトの url プロパティを変更します。
  3. url プロパティに有効な URL を割り当てます。HttpRequestTracker オブジェクトのその他のプロパティの変更は無視されます。
  4. true を返します。

すべてのネットワークリクエストの URL を変換することもできるので、最初の手順はオプションです。 

private static class myNetworkRequestCallback implements com.appdynamics.eumagent.runtime.NetworkRequestCallback  {
    @Override
    public boolean onNetworkRequest(HttpRequestTracker httpRequestTracker) {
        URL urlMask = new URL("http://networkrequest-mask.com/");
        httpRequestTracker.withURL(urlMask);
        return true;
    }
}
JAVA


ただし、一般的には機密情報が含まれている URL を特定して変換する必要があります。次に例を示します。

private static class myNetworkRequestCallback implements com.appdynamics.eumagent.runtime.NetworkRequestCallback  {
    @Override
    public boolean onNetworkRequest(HttpRequestTracker httpRequestTracker) {
        String urlString = httpRequestTracker.getURL().toString();
        try {
            URL url = new URL("http://customer-account.com/");
            if (urlString.contains("accountInfo")) {
                // Change the URL for calls to Facebook
                httpRequestTracker.withURL(url);
                return true;
            }
        } catch (MalformedURLException e) {
            return false;
        }
        return true;
    }
}
JAVA


URL の無視

onNetworkRequest メソッドが false を返した場合、ビーコンはドロップされます。ビーコンを無視する一般的なプロセスは次のとおりです。

  1. 正規表現やパターンマッチングなどの手法を使用して、特定の URL を識別します。

  2. false を返します。

onNetworkRequest の次の実装によってすべてのネットワークリクエストを無視することもできます。

private static class myNetworkRequestCallback implements com.appdynamics.eumagent.runtime.NetworkRequestCallback  {
    @Override
    public boolean onNetworkRequest(HttpRequestTracker httpRequestTracker) {
        return false;
    }
}
JAVA


一般的には、モニタしないネットワークリクエストを識別し、false を返して、ネットワークリクエストを無視します。次に例を示します。

private static class myNetworkRequestCallback implements com.appdynamics.eumagent.runtime.NetworkRequestCallback  {
    @Override
    public boolean onNetworkRequest(HttpRequestTracker httpRequestTracker) {
        String urlString = httpRequestTracker.getURL().toString();
        try {
            URL url = new URL("http://socialnetworksite.com/");
            if (urlString.contains("avatar")) {
                // Ignore calls for avatars
                return false;
            }
        } catch (MalformedURLException e) {
            return false;
        }
        return true;
    }
}
JAVA


ネットワーク要求のコールバックの登録

コールバックを実装した後、初期化コードに登録します。Android エージェントがネットワーク要求ビーコンを作成する準備ができたら、最初に HttpRequestTracker  オブジェクトを使用してコールバックを呼び出します。

初期化コードにコールバックを登録する場合は、次のようにします。

Instrumentation.start(AgentConfiguration.builder()
        .withContext(getApplicationContext())
        .withAppKey("<EUM_APP_KEY>")
        .withNetworkRequestCallback(new myNetworkRequestCallback())
        .build());
JAVA

ロギングの有効化とロギングレベルの設定

ロギングを有効にし、ロギングレベルを設定するには、AgentConfiguration クラスのメソッド withLoggingLevel を使用します。ロギングは、次のいずれかのレベルに設定できます。

  • LOGGING_LEVEL_NONE
  • LOGGING_LEVEL_INFO
  • LOGGING_LEVEL_VERBOSE

詳細ロギングは、トラブルシューティングにのみ使用します。実稼働環境では必ず無効にしてください。

Example:

AgentConfiguration config = AgentConfiguration.builder()
config.withAppKey(appKey)
config.withContext(context)
 .withLoggingLevel(Instrumentation.LOGGING_LEVEL_VERBOSE)
        .build();
    Instrumentation.start(config);
JAVA

Android SDK のドキュメント

SDK API の完全なマニュアルについては、次に示す最新の Java ドキュメントまたは以前のバージョンを参照してください。