Android インストゥルメンテーションのカスタマイズ
Android SDK を使用して Android アプリケーションをインストゥルメント化すると、SDK によって公開される API を使用して、コントローラ UI に表示されるアプリケーションのデータをカスタマイズすることもできます。以下のセクションでは、Android API を使用してインストゥルメンテーションをカスタマイズする方法について説明します。
データの追加タイプの収集
Instrumentation クラスには、モバイル RUM を使用して収集および集約できるアプリケーションデータの種類を拡張できる追加のメソッドがあります。作成できる拡張には、次の 6 つの基本タイプがあります。
| エクステンション | 説明 | 仕様 | コントローラ UI でデータが表示される場所 |
|---|---|---|---|
| 情報ポイント | メソッドが呼び出される頻度と実行される時間。 |
|
|
| カスタムタイマー | コード内の任意のイベントシーケンスが、複数のメソッドにまたがる場合でも、時間を計測します。 |
|
|
| カスタムメトリック | 収集する整数ベースのデータ。 |
|
|
| ユーザデータ |
有用と思われる任意の文字列キーと値のペアこのデータは、消去されるまで、リストされるすべてのインストゥルメンテーション タイプに含まれます。 |
|
|
| トピック パス(パンくずリスト) | クラッシュのコンテキスト。 |
|
|
| ユーザインタラクション | ユーザーがボタンを押したとき、リストをクリックしたとき、およびテキストを選択したときにキャプチャします。 |
|
情報ポイント、カスタムタイマー、カスタムメトリック、ユーザデータを設定した場合、モバイルエージェントはモバイルビーコンでそのデータをパッケージ化します。通常、ビーコンは、インストゥルメント化されたアプリケーションが 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_ONLYCRASHES_AND_SESSIONS
breadcrumb が 2048 文字を超えている場合は、切り捨てられます。空の場合、トピック パス(パンくずリスト)は記録されません。各クラッシュレポートには、最近の 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 アナリティクスなどの別の分析ツールに情報を送信する場合は、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 ドキュメントを参照してください。
クラッシュレポートの無効化
クラッシュレポートはデフォルトで有効になっていますが、インストゥルメンテーション構成を使用して手動でクラッシュレポートを無効にできます。他のクラッシュレポートツールを使用している場合、競合を最小限に抑え、クラッシュレポートの結果を最適化するために、クラッシュレポートを無効にする場合があります。
次に示すように、crashReportingEnable プロパティを使用してインストルメンテーションを構成することにより、クラッシュレポートを無効にできます。
let config = ADEumAgentConfiguration(appKey: <#EUM_APP_KEY#>);
config.crashReportingEnabled = false;
ADEumInstrumentation.initWith(config);
エラーと例外のレポート
reportError に使用される新しい throwable の構成に使用される文字列メッセージでは、ハッシュ、StackTraceID、または ThreadID などの一意の文字列を使用しないでください。これらの文字列を含めると、Error Group が無数に作成され、パフォーマンスに影響を与えます。
一意のエラー文字列と値を追加するには、次の 2 つのデータ収集オプションがあります。
- トピックパスとして文字列値を追加します。報告するイベント/エラーに単一の値が添付されている場合は、その値を
leaveBreadcrumbに追加します。「トピックパス(パンくずリスト)」を参照してください - 文字列名と整数値を追加します。報告するイベント/エラーに名前と整数値の両方が添付されている場合は、その値を
reportMetricに追加します。「カスタムメトリック」を参照してください。
クラスの メソッドを使用して例外を報告できます。報告された例外は、セッション詳細に表示されます。
また、問題に対して次のシビラティ(重大度)レベルの 1 つを設定することもできます。シビラティ(重大度)レベルを使用すると、[Code Issues Dashboard] または [Code Issues Analyze] でエラーをフィルタ処理できます。
ErrorSeverityLevel.INFOErrorSeverityLevel.WARNINGErrorSeverityLevel.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 つのメソッドを示します。
| クラス | メソッド | 説明 |
|---|---|---|
インストルメンテーション |
CODE
|
セッションフレームを開始して名前を付けるには、これを使用します。 セッションフレームに命名すると、セッションダイアログ内のフレームを簡単に特定して追跡できます。 |
SessionFrame |
CODE
|
セッションフレームを開始して名前を付けるには、これを使用します。 セッションフレームに命名すると、セッションダイアログ内のフレームを簡単に特定して追跡できます。 |
SessionFrame |
CODE
|
セッションフレームを終了します。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;
}
}
Use a Custom HTTP Library
The Android Agent automatically detects network requests when the underlying implementation is handled by any one of the supported network libraries. To have the Android Agent detect requests from a custom library, add request tracking code to your application manually, using the HttpRequestTracker interface.
Supported Network Libraries
The libraries below cover the great majority of Android network requests. In some cases, however, mobile applications use custom HTTP libraries.
HttpURLConnectionHttpsURLConnectionHttpClientclassesOkHttpOkHttp3ch.boye.httpclientandroidlib
To ServerCorrelationHeaders set headers to allow correlation with server-side processing, use the ServerCorrelationHeaders class.
Add Request Tracking
To add request tracking manually, you use an HttpRequestTracker object to tell the agent when the request begins and when it ends and to report fields of the response to the agent.
Start Tracking a Request
To begin tracking an HTTP request, use an instance of the following interface.
You must initialize the agent using the Instrumentation.start method before using this interface.
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();
}
Example
Given a request snippet like this:
public byte[] sendRequest(URL url) throws HttpException {
try {
// implementation omitted
return responseBody;
} catch (UnderlyingException e) {
throw new HttpException(e);
}
}
Adding the tracker could look like this:
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);
}
}
Attach a Custom User Data Property to a Network Request
You can attach a HttpRequestTracker custom user data property to a specific network request by adding user data to 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)
Example
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);
}
}
Enable Server-Side Correlation
To enable correlation between your request and server-side processing, add specific headers to outgoing requests that the server-side agent can detect.
This is done automatically for standard HTTP libraries.
public class ServerCorrelationHeaders {
public static Map<String, List<String>> generate();
}
You must:
- Call the
generatemethod and set the generated headers before sending a request to the backend. - Report back the response headers, using data from the
withResponseHeaderFieldsfield.
Override the Request/Response Content-Length
- You can generally obtain the content lengths of the network request and response by passing the headers with
HttpRequestTracker.withRequestHeaderFields()andHttpRequestTracker.withResponseHeaderFields(). -
If for some reason this does not work for your custom HTTP tracking (i.e. the network library doesn't populate those fields until its being transmitted), then you can still report the request and response content lengths using
HttpRequestTracker.withRequestContentLength(Long length)andHttpRequestTracker.withResponseContentLength(Long length). -
For example, you want to track a request that has a
bytearray of content. You can report the request content length by passing the size of the byte array:
byte[] requestContent;
HttpRequestTracker tracker;
tracker.withRequestContentLength(requestContent.size());
エージェント設定のカスタマイズ
エージェント自体の動作をカスタマイズするには、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());
EUM サーバーの URL のリストについては、「Splunk AppDynamics オンプレミス ドメインと IP 範囲」を参照してください。
カスタム HTTP ライブラリを使用するようにエージェントを設定する
Android エージェントは、ビーコンを配信するために HTTP を使用します。エージェントがカスタム HTTP ライブラリを使用してビーコンを配信する場合は、次の手順を実行します。
-
次の抽象クラスを拡張するクラスを実装します。
CODEpublic 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; }このインターフェイスは、おおむね HttpURLConnection に基づいています。
-
CollectorChannelFactoryインターフェイスのバージョンを実装します。PYTHONpublic 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(); }newCollectorChannelの実装は、CollectorChannelの実装の新しいインスタンスを返す必要があります。 -
CollectorChannelFactoryをAgentConfigurationオブジェクトに渡します。
ユーザインタラクションのキャプチャ
特定のユーザインタラクションをトラッキングするように、エージェントを有効化できます。ユーザインタラクションがキャプチャされると、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;
}
}
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_NONELOGGING_LEVEL_INFOLOGGING_LEVEL_VERBOSE
詳細ロギングは、トラブルシューティングにのみ使用します。実稼働環境では必ず無効にしてください。
例:
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/