Android インストルメンテーションのカスタマイズ
Android SDK を使用して Android アプリケーションをインストゥルメント化すると、SDK によって公開される API を使用して、コントローラ UI に表示されるアプリケーションのデータをカスタマイズすることもできます。以下のセクションでは、Android API を使用してインストルメンテーションをカスタマイズする方法について説明します。
データの追加タイプの収集
Instrumentation クラスには、モバイル RUM を使用して収集および集約できるアプリケーションデータの種類を拡張できる追加のメソッドがあります。作成できる拡張には、次の 6 つの基本タイプがあります。
| エクステンション | 説明 | 仕様 | コントローラ UI でデータが表示される場所 |
|---|---|---|---|
| 情報ポイント | メソッドが呼び出される頻度と実行される時間。 |
| |
| カスタムタイマー | コード内の任意のイベントシーケンスが、複数のメソッドにまたがる場合でも、時間を計測します。 |
| |
| カスタムメトリック | 収集する整数ベースのデータ。 |
| |
| ユーザデータ |
有用と思われる任意の文字列キーと値のペアこのデータは、消去されるまで、リストされるすべてのインストルメンテーション タイプに含まれます。 |
| |
| トピック パス(パンくずリスト) | クラッシュのコンテキスト。 |
| |
| ユーザインタラクション | ユーザーがボタンを押したとき、listsをクリックしたとき、およびテキストを選択したときにキャプチャします。 |
|
情報ポイント、カスタムタイマー、カスタムメトリック、ユーザデータを設定した場合、モバイルエージェントはモバイルビーコンでそのデータをパッケージ化します。通常、ビーコンは、インストゥルメント化されたアプリケーションが HTTP リクエストを送信したとき、またはクラッシュ後にアプリケーションが起動したときに、送信されますが、カスタムデータが収集済みで、これらのイベントが少なくとも 5 分間発生しなかった場合、カスタムデータはその時点で送信されます。
情報ポイント
情報ポイントを使用すると、独自のコードがどのように実行されているかを追跡できます。メソッドが呼び出される頻度、実行にかかる時間、および例外がスローされたかどうかを確認できます。情報ポイントを設定する最も簡単な方法は、@InfoPoint 注釈を使用することです。例:
@InfoPoint
public void infoPointMethod(String arg1, int arg2, long value) {
System.out.println("Executing infoPointMethod!");
}
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);
}
}
この情報は、コントローラ UI の [Custom Data] ビューに表示されます。
カスタムタイマー
カスタムタイマーでは、複数のメソッドにまたがる場合でも、startTimer と stopTimer を使用して、コード内の任意のイベントシーケンスの時間を測定できます。
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.
}
}
メソッド 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);
}
});
この情報は、コントローラ UI の [Custom Data] ビューに表示されます。
Custom User Data
setUserData(key, value, success, error) メソッドで役立つ任意の文字列キーや値のペアを設定し、後で削除できます。
これが設定されると、アプリケーションの現在の実行の残りについて、ユーザーデータは、ネットワークリクエスト、セッション、またはクラッシュのインストゥルメンテーションとともに引き続き送信されます。以前に設定されたユーザーデータはキーごとに削除できます。または、clearAllUserData を使用して、すべてのキーの以前に設定されたユーザーデータを一度に削除できます。
パラメータ
次の表で、パラメータについて説明します。
| Name | タイプ | 説明 |
|---|---|---|
| キー | 文字列 | キーと値のペアを識別するキー。 |
| 値 | 文字列 | キーに関連付けられている値。 |
| success | function | ユーザ定義のコールバックの成功例。 |
| error | function | ユーザ定義のコールバックの失敗例。 |
例
次のコード例は、SDK API を使用してユーザーデータを設定する方法を示しています。
void onUserLoggedIn(String userid) {
Instrumentation.setUserData("User ID", userid);
...
}
この情報は、[Network Request Analyze] で確認でき、クラッシュスナップショットに追加されます。キーと値はそれぞれ 2048 文字に制限されています。
また、次のメソッドを使用して、他のデータ型(Long、Boolean、Double、Date)の値を含むユーザデータを設定することもできます。
トピックパス(パンくずリスト)
トピックパスを使用すると、ユーザエクスペリエンスのコンテキストでクラッシュの場所を特定できます。一連のイベントをキャプチャする場合は、トピックパスを設定します。その後のある時点でアプリケーションがクラッシュした場合、トピックパスはクラッシュレポートとともに表示されます。
トピックパスを残すには、次の 2 つの方法があります。
- クラッシュレポートのみ
- モーダル
クラッシュレポートのみ
次のメソッドを使用すると、トピックパスがクラッシュレポートのみで報告されます。
public static void leaveBreadcrumb(java.lang.String breadcrumb)
モーダル
次のメソッドを使用すると、トピックパスが報告される場所を微調整(クラッシュレポートのみ、またはクラッシュレポートとセッションを選択)できます。
public static void leaveBreadcrumb(java.lang.String breadcrumb, int mode)
モードは次のいずれかです。
-
CRASHES_ONLY -
CRASHES_AND_SESSIONS
breadcrumb は 2,048 文字を超えている場合、切り捨てられます。空の場合、トピック パス(パンくずリスト)は記録されません。各クラッシュレポートには、最近の 99 件のトピックパスが表示されます。
クラッシュ レポート コールバックの追加
コードの他の部分(Google アナリティクスなど)が Android エージェントにより収集されるクラッシュレポート情報を使用できるようにすることがあります。サマリークラッシュ情報を渡すことができるようにするには、クラッシュレポートのランタイムコールバックを設定します。Android エージェントがクラッシュを検出して報告するときに、コールバックを取得するには、コードに次のインターフェイスを実装します。
public interface CrashReportCallback {
void onCrashesReported(Collection<CrashReportSummary> summaries);
}Android エージェントは、複数のクラッシュがあり、複数のクラッシュレポート概要が生成される場合、個々のコールバックではなく、一連のクラッシュレポート概要を送信します。
メソッド onCrashesReported は、クラッシュ発生後の Android エージェントの初期化中に呼び出されます。
このコールバックはアプリケーションの UI スレッドで呼び出されるため、作業は別の作業スレッドで実行する必要があります。
各 CrashReportSummary に次のプロパティがあります。
public class CrashReportSummary {
public final String crashId;
public final String exceptionClass;
public final String exceptionMessage;
}Google Analytics などの別の分析ツールに情報を送信する場合は、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 + ")");
}
}
}AgentConfiguration オブジェクトを使用してコールバックを設定します。
final AgentConfiguration config = AgentConfiguration.builder()
.withAppKey(appKey)
.withContext(context)
.withCrashCallback(new MyCrashReportCallback())
.build();コールバックは、メインスレッドで、クラッシュ後の次の初期化中に呼び出されます。詳しくは、Android SDK API の最新の Java ドキュメントを参照してください。
クラッシュレポートの無効化
クラッシュレポートはデフォルトで有効になっていますが、インストルメンテーション構成を使用して手動でクラッシュレポートを無効にできます。他のクラッシュレポートツールを使用している場合、競合を最小限に抑え、クラッシュレポートの結果を最適化するために、クラッシュレポートを無効にする場合があります。
次に示すように、crashReportingEnabled プロパティを使用してインストゥルメンテーションを構成することにより、クラッシュレポートを無効にできます。
let config = ADEumAgentConfiguration(appKey: <#EUM_APP_KEY#>);
config.crashReportingEnabled = false;
ADEumInstrumentation.initWith(config);エラーと例外のレポート
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);
}
}コレクタへのユーザデータの送信を停止する場合のエージェントの無効化
エージェントの初期化中および実行中に、エージェントを無効にしてコレクタへのすべてのデータの送信を停止できます。たとえば、プライバシー上の理由でユーザがモニタリングをオプトアウトするオプションがアプリにある場合は、エージェントを無効にできます。
shutdownAgent
shutdownAgentコールはコレクタへの発信データを停止し、デバイスにデータを保持しません。
Instrumentation.shutdownAgent();
- このコールは、エージェントからのトラフィックのみを停止します。
- エージェントが初期化されると、コールは削除できず、ライセンスが消費されます。
- この状態をデバイスで永続的にする場合は、
UserDefaultsにコードを追加して状態を保存し、そのフラグを使用してコード内のエージェントを条件付きで初期化します。
restartAgent
エージェントを再度有効にして shutdownAgent を無効にする場合は、restartAgent を使用します。
Instrumentation.restartAgent();
- このコールは、同様にリモートでエージェントをシャットダウンできるサーバ側のコールにも対応します。
- コールは、アプリケーションの実行中にのみ有効です。
- エージェントがリモートで無効になっている場合、コールは無視されます。
- コールがメモリから削除され、アプリケーションが再起動されるか、デバイスが再起動されると、エージェントは通常どおり初期化されます。
ハイブリッドサポートの設定
デフォルトでは、Android エージェントは JavaScript エージェントを WebView に挿入して、 Android WebView をインストルメント化します。この機能の概要と説明については、「ハイブリッド アプリケーションのサポート」を参照してください。
ハイブリッドサポートのランタイム設定
次のコード例では、JavaScript エージェントのインジェクションを無効にしています。クライアントがこのフラグに false を受け取ると、JavaScript エージェントは無効になります。そのため、WebView はインストルメント化されず、Ajax リクエストはモニターされません。
Instrumentation.start(
AgentConfiguration.builder()
.withAppKey(getString(R.string.app_key))
.withContext(applicationContext)
.withJSAgentInjectionEnabled(false)
.build())
インジェクションは、新しい WKWebView の作成時に発生します。このため、このフラグが false に設定されているときに WKWebView が作成された場合、その特定の WKWebView は、 その後フラグが true に設定されてもインストゥルメント化されません。
Ajax コールの収集およびレポートは、デフォルトでは無効になっています。Ajax コールのインジェクションおよび収集とレポートを有効にするには、次に示すようにインストルメンテーションの構成でメソッド jsAgentEnabled に true を渡します。
Instrumentation.start(
AgentConfiguration.builder()
.withAppKey(getString(R.string.app_key))
.withContext(applicationContext)
.withJSAgentAjaxEnabled(true)
.build())
プログラムによるセッションの制御
デフォルトでは、ユーザが非アクティブになってからモバイルセッションが終了します。たとえば、ユーザがアプリケーションを開くと、セッションは開始され、ユーザが設定した期間にアプリケーションを使用しなくなった後にのみ終了します。ユーザがアプリケーションの再使用を開始すると、新しいセッションが開始されます。
ただし、セッションの期間を定義するのに非アクティブな期間を設定する代わりに、次の API を使用して、セッションの開始と終了をプログラムで制御できます。
void startNextSession()インストゥルメンテーション クラスからメソッド 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");
}
}
セッションフレームの開始と終了
SessionFrame API を使用して、セッションアクティビティに表示されるセッションフレームを作成できます。セッションフレームは、セッション中にユーザが実行している内容のコンテキストを提供します。この API を使用すると、ユーザ画面の命名方法が向上し、ビジネスコンテキスト内のユーザフローを記録できます。
使用例
次に、SessionFrame API の一般的なユースケースを示します。
- 1 つのアクティビティが複数の機能を実行し、個々の機能をより詳細に追跡します。
- ユーザフローは、複数のアクティビティまたはユーザのインタラクションに及びます。たとえば、API を使用してセッションフレーム「Login」、「Product Selection」、および「Purchase」を作成して、ユーザが購入のためにフローを記録することができます。
- ユーザの操作に基づいて動的情報をキャプチャし、オーダー ID などのセッションフレームに名前を付けることができます。
SessionFrame API
次の表に、セッションフレームで使用できる 3 つのメソッドを示します。
| クラス | メソッド | 説明 |
|---|---|---|
Instrumentation |
|
セッションフレームを開始して名前を付けるには、これを使用します。 セッションフレームに命名すると、Sessions Dialog. のフレームを簡単に識別して追跡できます。 |
SessionFrame |
|
セッションフレームを開始して名前を付けるには、これを使用します。 セッションフレームに命名すると、Sessions Dialog. のフレームを簡単に識別して追跡できます。 |
SessionFrame |
| セッションフレームを終了します。SessionFrame から返された startSessionFrame オブジェクトからこのメソッドを呼び出すことができます。 |
セッションフレームの例
次の例では、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;
}
}
カスタム HTTP ライブラリの使用
基盤となる実装がサポートされているいずれかのネットワークライブラリによって処理されると、Android エージェントは自動的にネットワーク要求を検出します。Android エージェントがカスタムライブラリからの要求を検出するようにするには、HttpRequestTracker インターフェイスを使用してアプリケーションに手動で要求トラッキングコードを追加します。
サポート対象のネットワークライブラリ
以下のライブラリは、Android ネットワーク要求の大部分をカバーしています。ただし、モバイルアプリケーションでは、カスタム HTTP ライブラリが使用される場合があります。
-
HttpURLConnection -
HttpsURLConnection HttpClientクラス-
OkHttp -
OkHttp3 -
ch.boye.httpclientandroidlib
サーバー側の処理との相関を許可するようにヘッダーを設定するには、ServerCorrelationHeaders クラスを使用します。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();
}
例
次のようなリクエストスニペットがあるとします。
public byte[] sendRequest(URL url) throws HttpException {
try {
// implementation omitted
return responseBody;
} catch (UnderlyingException e) {
throw new HttpException(e);
}
}
トラッカーを追加すると、次のようになります。
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);
}
}
ネットワークリクエストへのカスタム ユーザー データ プロパティの追加
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)
例
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);
}
}
サーバー側の相関を有効にする
要求とサーバ側の処理の相関を有効にするには、サーバ側のエージェントが検出できる発信要求に特定のヘッダーを追加します。
これは、標準 HTTP ライブラリに対して自動的に実行されます。
public class ServerCorrelationHeaders {
public static Map<String, List<String>> generate();
}
次の作業が必要です。
- バックエンドにリクエストを送信する前に、
generateメソッドを呼び出し、生成されたヘッダーを設定します。 withResponseHeaderFieldsフィールドのデータを使用して、応答ヘッダーを報告します。
要求/応答のコンテンツ長をオーバーライドする
- 通常は、
HttpRequestTracker.withRequestHeaderFields()とHttpRequestTracker.withResponseHeaderFields()を使用してヘッダーを渡すことで、ネットワーク要求と応答のコンテンツ長を取得できます。 -
何らかの理由でこれがカスタム HTTP トラッキングに対して機能しない場合(つまり、ネットワークライブラリが送信されるまでこれらのフィールドにデータを入力しない場合)でも、
HttpRequestTracker.withRequestContentLength(Long length)およびHttpRequestTracker.withResponseContentLength(Long length)を使用して要求と応答のコンテンツの長さを報告できます。 -
たとえば、コンテンツが
byte配列の要求をトラッキングするとします。次のように、バイト配列のサイズを渡すことで、要求のコンテンツの長さを報告できます。
byte[] requestContent;
HttpRequestTracker tracker;
tracker.withRequestContentLength(requestContent.size());
Customize the Agent Configuration
To customize the behavior of the agent itself, you pass the AgentConfiguration object to the Instrumentation.start method. The AgentConfiguration object allows you to:
- Point to an on-premises EUM Server
- Enable logging
- Custom-set the application name, which is useful if you deploy the same application binary with different package names to different geographic areas. This ensures that all the data ends up being processed under the same name.
- Ignore HTTP requests internal to your application that are not used for network requests
- Configure the agent to use your custom HTTP library to send its beacons
Syntax
See the latest JavaDocs for more information.
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());
For a list of URLs of EUM servers, see Domains and IP Ranges.
Configure the Agent to Use Custom HTTP Library
The Android Agent uses HTTP to deliver beacons. If you want the agent use your custom HTTP library to deliver beacons:
-
Implement a class that extends the following abstract class:
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; }This interface is loosely based on HttpURLConnection.
-
Implement a version of the
CollectorChannelFactoryinterface: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(); }The implementation of
newCollectorChannelshould return a new instance of your implementation ofCollectorChannel. -
Pass the
CollectorChannelFactoryto theAgentConfigurationobject.
ユーザインタラクションのキャプチャ
特定のユーザインタラクションをトラッキングするように、エージェントを有効化できます。ユーザインタラクションがキャプチャされると、UI イベントごとにセッションをソートし、セッション ウォーターフォールのタイムラインで UI イベントを表示することができます。
ユーザが次のいずれかまたはすべてを実行するときにキャプチャできます。
- ボタンのクリック
- テキストフィールドの選択
- リスト項目のクリック
セキュリティおよびプライバシー上の懸念点
インタラクション キャプチャ モードは、セキュリティとプライバシー上の理由でデフォルトでは無効になっています。これは、ユーザインタラクションに機密情報が含まれている可能性があるためです。UI インタラクションとスクリーンショットのキャプチャの両方を有効にすると、このような潜在的なセキュリティとプライバシー上の問題が複合化する場合があります。
ユーザ インタラクション キャプチャ モードの有効化
ユーザーインタラクションのキャプチャモードを有効にするには、AgentConfigurationオブジェクトからメソッド withInteractionCaptureMode() にキャプチャモードを渡します。次のインストゥルメンテーション コードの例では、サポート対象のすべてのタイプのユーザインタラクションをキャプチャするように Android エージェントを設定します。
Instrumentation.start(AgentConfiguration.builder()
.withAppKey("<EUM_APP_KEY>")
.withContext(getApplicationContext())
.withInteractionCaptureMode(InteractionCaptureMode.All)
.build());
また、1 つのタイプのユーザインタラクションのみをキャプチャするように Android エージェントを設定することもできます。
Instrumentation.start(AgentConfiguration.builder()
.withAppKey("<EUM_APP_KEY>")
.withContext(getApplicationContext())
.withInteractionCaptureMode(InteractionCaptureMode.ButtonPressed)
.build());
プログラムによるスクリーンショットの取得
デフォルトでは、モバイルスクリーンショットはエージェント側で有効になりますが、コントローラ側では無効になります。プログラムで手動でスクリーンショットを取得するには、コントローラ UI でスクリーンショットを有効にし、次の API を追加する必要があります。
Instrumentation.takeScreenshot();たとえば、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();
}スクリーンショットの無効化
コントローラ UI からまたは Android SDK を使用すると、スクリーンショットを無効にすることができます。Android SDK を使用してスクリーンショットを無効にするには、AgentConfiguration クラスからメソッド withScreenshotsEnabled(false) を使用します。
Instrumentation.start(AgentConfiguration.builder()
.withAppKey("<EUM_APP_KEY>")
.withContext(getApplicationContext())
.withScreenshotsEnabled(false)
.build());
}
スクリーンショットのブロック/ブロック解除
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();
}
...
}ネットワークリクエストに対応した URL の変換
アプリケーションがネットワークリクエストを行う場合、機密情報が含まれている URL を EUM サーバに報告したくない場合があります。その場合は、ネットワークリクエスト URL を報告する前に変換するか、すべて無視します。
- 特定の URL を変更または無視するネットワーク リクエスト コールバックを実装します。
- 初期化コードにネットワーク リクエスト コールバックを登録します。
特定の URL を変更または無視するコールバックは、次のインターフェイスの実装です。onNetworkRequest メソッドは同期されているため、関数からすばやく戻ることを推奨します。
public interface com.appdynamics.eumagent.runtime.NetworkRequestCallback {
boolean onNetworkRequest(HttpRequestTracker httpRequestTracker);
}
URL の変換
通常 、onNetworkRequest メソッドは次の手順に従って URL を変換する必要があります。
- 正規表現やパターンマッチングなどの手法を使用して、特定の URL を識別します。
HttpRequestTrackerオブジェクトのurlプロパティを変更します。urlプロパティに有効な URL を割り当てます。HttpRequestTrackerオブジェクトのその他のプロパティの変更は無視されます。trueを返します。
すべてのネットワークリクエストの URL を変換することもできるので、最初の手順はオプションです。ただし、一般的には、機密情報が含まれている 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;
}
}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;
}
} URL の無視 onNetworkRequest メソッドが false を返した場合、ビーコンはドロップされます。ビーコンを無視する一般的なプロセスは次のとおりです。
- 正規表現やパターンマッチングなどの手法を使用して、特定の URL を識別します。
falseを返します。
また、onNetworkRequest の次の実装によってすべてのネットワークリクエストを無視することもできます。一般的には、モニターしないネットワークリクエストを識別し、false を返して、ネットワークリクエストを無視します。
private static class myNetworkRequestCallback implements com.appdynamics.eumagent.runtime.NetworkRequestCallback {
@Override
public boolean onNetworkRequest(HttpRequestTracker httpRequestTracker) {
return 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;
}
}ネットワーク要求のコールバックの登録
コールバックを実装した後、初期化コードに登録します。Android エージェントがネットワーク要求ビーコンを作成する準備ができたら、最初に HttpRequestTracker オブジェクトを使用してコールバックを呼び出します。
初期化コードにコールバックを登録する場合は、次のようにします。
Instrumentation.start(AgentConfiguration.builder()
.withContext(getApplicationContext())
.withAppKey("<EUM_APP_KEY>")
.withNetworkRequestCallback(new myNetworkRequestCallback())
.build());
ロギングの有効化とロギングレベルの設定
ロギングを有効にし、ロギングレベルを設定するには、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);Android SDK のドキュメント
SDK API の完全なマニュアルについては、次に示す最新の Java ドキュメントまたは以前のバージョンを参照してください。
Android SDK のドキュメント
SDK API の完全なマニュアルについては、次に示す最新の Java ドキュメントまたは以前のバージョンを参照してください。
- https://sdkdocs.appdynamics.com/android-sdk/22.8/
- https://sdkdocs.appdynamics.com/android-sdk/22.2/
- https://sdkdocs.appdynamics.com/android-sdk/22.1/
- https://sdkdocs.appdynamics.com/android-sdk/21.11/
- https://sdkdocs.appdynamics.com/android-sdk/21.6/
- https://sdkdocs.appdynamics.com/android-sdk/21.5/
- https://sdkdocs.appdynamics.com/android-sdk/21.2/
- https://sdkdocs.appdynamics.com/android-sdk/20.11/
- https://sdkdocs.appdynamics.com/android-sdk/20.10/
- https://sdkdocs.appdynamics.com/android-sdk/20.7/
- https://sdkdocs.appdynamics.com/android-sdk/20.5/
- https://sdkdocs.appdynamics.com/android-sdk/20.3/