📱

Android アプリに Splunk Observability RUM を組み込む

2023/11/21に公開

Hi, Splunk Observability の導入支援を行っている、kntr_nkgm です。
今回は、Android アプリに対して、RUM の導入を行っていきます。

RUM (Real User Monitoring) は、実ユーザによるブラウザ処理やアプリでの操作の際の体感、エラーやクラッシュの発生状況などを取得・可視化してくれる機能です。
個人的な体感としては、仕事や何らかの作業をしている場合はパソコンの前に座って、Webブラウザで何かを検索したり、登録したり、注文したりすることが多い気がしますが、日常生活においては、アプリで色んなことを済ませる機会の方が多いような印象です。
モバイルアプリを、特に一般の方々に公開されている方からすると、利用ユーザが実際にどんな体感を得ているのか(快適にアプリを使ってくれているか、使いづらくてアプリをアンインストールしたりしないか)というのは、気になるポイントなのではないでしょうか。

Splunk Observability では、モバイルアプリに対する RUM の導入が可能です。
Android, iOS ともに対応しており、また、OpenTelemetry をベースとした実装なので、Splunk 以外のバックエンドも選択しうる(ベンダーロックインが少ない)という点でも安心できるものだと思います。

前提

Android Studio は導入済みの状態からスタートします。
また、Java も導入済みの状態です(私の環境では、OpenJDK 21.0.1 を導入済み)

アプリケーションを0から作るのも大変なので、Android が公開しているサンプルコード Jetpack Compose を拝借することにします。
その中でも、今回は、Jetsurvey で試してみました。

サンプルコードの利用方法は、以下のページを参照してください。
https://developer.android.com/jetpack/compose/setup?hl=ja#sample

Splunk RUM の導入

基本的にすべてのデータ取得は、ガイドインストール画面から実施できます。
今回は、"Monitor User Experience" → "Android Instrumentation" からスタートしていきます。

ガイドインストール画面

その後はガイドの中で、Access Token を指定したり、

アプリケーションの名前や環境名を指定したりします。

すると、こんな感じで、導入方法のガイドが表示されます。

以下、これに従いながらセットアップを行っていきます。

desugar 設定(今回は割愛)有効化のオプションを追加

Android API レベルが 21 から 25 の場合は、desugar 設定の有効化が必要となります。
今回は最新の API レベルを使用することにして、割愛しました。

Android Agent を依存関係に追加

まず、 mavenCentral() からライブラリを取得するように設定されているかを確認します。
今回のサンプルアプリでは、settings.gradle.kts ファイル内で、以下のように設定されていますので、問題なさそうです。

settings.gradle.kts
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        snapshotVersion?.let {
            println("https://androidx.dev/snapshots/builds/$it/artifacts/repository/") 
            maven { url = uri("https://androidx.dev/snapshots/builds/$it/artifacts/repository/") }
        }

        google()
        mavenCentral()    // 既に入っているのでOK
    }
}

では、次に、アプリケーションの依存関係として、Android Agent を追加していきましょう。
build.gradle.kts 内の dependencies 句に以下を追加します。

build.gradle.kts
dependencies {
    // 省略
    //
    implementation("com.splunk:splunk-otel-android:+")
    implementation("io.opentelemetry.android:instrumentation:0.2.0-alpha")
    //
    // 省略
}

この時点でビルドをかけて、特に問題ないかを一応確認しておきます。

Android RUM agent の初期化・構成

さて、次に、アプリ起動のタイミングで、Android RUM agent がデータ取得を開始できるように設定を行っていきます。
Android アプリでは、最初の Activity 開始直後に onCreate() が呼びだされますので、その直後に、Android RUM Agent を初期化するようにします。
今回のアプリケーションは、app > java > com.example.compose.jetsurveyMain Activity.kts 内に、onCreate() が含まれているようです。

MainActivity.kt
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
/* 以下略

まず、必要なライブラリをインポートします。

MainActivity.kt
import com.splunk.rum.SplunkRum
import com.splunk.rum.StandardAttributes
import io.opentelemetry.api.common.Attributes

続いて、MainActivity クラス内で、Splunk Observability にデータ送信するのに利用する realmrumAccessToken を設定します。

MainActivity.kt
class MainActivity : AppCompatActivity() {
    // 以下2行を追加
    // "<>" 内にはいずれも、ガイドセットアップでの設定や利用環境に応じた文字列が入ります
    private val realm = "<Realm>"
    private val rumAccessToken = "<RUM Access Token>"

更に、onCreate() の直後に、以下の行を追加します。

MainActivity.kt
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // ここから追加
        SplunkRum.builder()
            .setApplicationName("jetsurvey-sample")  // アプリケーション名
            .setDeploymentEnvironment("mobile-rum")  // 環境名
            .setRealm(realm)
            .setRumAccessToken(rumAccessToken)
            .setGlobalAttributes(
                Attributes.builder() // Add the application version. Alternatively, you
                    // can pass BuildConfig.VERSION_NAME as the value.
                    .put(StandardAttributes.APP_VERSION, "1.0.0")
                    .build()
                    // Turn off instrumentation of background processes
                    //.disableBackgroundTaskReporting(BuildConfig.<id_of_application>
                    )
                    // Enables debug logging if needed
		    // .enableDebug()
                    .build(applicationContext as Application?)

    // 追加はここまで
        setContent {
            JetsurveyTheme {
                JetsurveyNavHost()
            }
        }
    }

とりあえず、これでセットアップは終了です。
なお、HTTPクライアントに対して追加の計装を行うようなことも可能ですが、今回のサンプルアプリでは割愛しています。

アプリケーションを再ビルドしてエラーがでなければ、アプリを動かしてみましょう。
私は、Android Studio の Device Manager から、Pixel 7 Pro (API レベル 31) の仮想デバイスを作成して、その上で動かしてみました。

このアプリケーションは、Survey という名前の通り、いくつかの質問事項を提示し、ユーザーに回答をさせるものです。
仮想デバイス上で操作をしていくと、Logcat 画面上にも、Splunk RUMOpenTelemetry Rum という文字が見えますね。
画像ファイルは、ちょっと小さくなってしまいましたので、一部抜粋。

2023-11-21 15:26:11.939 12642-12877 LoggingSpanExporter     com.example.compose.jetsurvey        I  'SplunkRum.initialize' : 5c8c3e724f119acbd7feb6e62b81ccc9 90edc6d06e7c9d56 INTERNAL [tracer: SplunkRum:] AttributesMap{data={app.version=1.0.0, session.id=244482e977893c45a84b9223305ea60b, network.carrier.mcc=310, network.connection.type=wifi, config_settings=[debug:true,crashReporting:true,anrReporting:true,slowRenderingDetector:true,networkMonitor:true], network.carrier.icc=us, network.carrier.mnc=260, screen.name=unknown, component=appstart, network.carrier.name=T-Mobile - US}, capacity=128, totalAddedValues=10}
2023-11-21 15:26:11.939 12642-12877 LoggingSpanExporter     com.example.compose.jetsurvey        I  'AppStart' : 5c8c3e724f119acbd7feb6e62b81ccc9 0bb66cd7129caf0a INTERNAL [tracer: SplunkRum:] AttributesMap{data={start.type=cold, app.version=1.0.0, session.id=244482e977893c45a84b9223305ea60b, network.carrier.mcc=310, network.connection.type=wifi, network.carrier.icc=us, network.carrier.mnc=260, screen.name=unknown, component=appstart, network.carrier.name=T-Mobile - US}, capacity=128, totalAddedValues=10}
2023-11-21 15:26:11.940 12642-12877 LoggingSpanExporter     com.example.compose.jetsurvey        I  'Restarted' : e8bb22b05a6acc1658867fdecdd5f9a5 5c573e0663bfc668 INTERNAL [tracer: io.opentelemetry.lifecycle:] AttributesMap{data={app.version=1.0.0, session.id=244482e977893c45a84b9223305ea60b, network.carrier.mcc=310, network.connection.type=wifi, network.carrier.icc=us, activityName=MainActivity, network.carrier.mnc=260, screen.name=MainActivity, component=ui, network.carrier.name=T-Mobile - US}, capacity=128, totalAddedValues=11}
2023-11-21 15:26:12.014 12642-12883 SplunkRum               com.example.compose.jetsurvey        D  Sending 3 spans for export
2023-11-21 15:26:12.372 12642-12642 OpenTelemetryRum        com.example.compose.jetsurvey        D  Detected background app start

Splunk Observability の画面では、やや物寂しいですが、私が操作した時の情報が表示されます。


ホーム画面

詳細画面

タグ別の傾向分析

特定ユーザーセッションの操作情報

モバイルアプリケーションへの RUM では、たとえば、以下のような情報に関するメトリクスやイベントが取得されます。

  • アプリケーションの起動所要時間(App Launch, Cold Start, Hot Start...)
  • クラッシュ・エラー・ANRなどのイベント
  • カスタムイベント

また、例えば、デバイス情報(デバイス名・OS・OSバージョンなど)や、アプリケーションのビルド名、地理的な情報などの属性値をあわせて設定してくれますので、これらに基づいて大まかな傾向を理解することができます。

一方で、より詳細な調査を行う上では、アプリケーションの特性に合わせた/調査や傾向分析のために必要な情報を属性として個別に付与したり、カスタムイベントとして設定することで、問題分析に活用することができます。
こういったマニュアル計装は、今後の記事に回すこととします。

おわりに

Java/kotlin のコード自体は多少なりと触れたことはあったものの、Android アプリに手を出す機会はこれまであまりなかったのもあり、私自身も良い勉強になりました。
Android Studioさんが色々と示唆してくれるのは助かりますね。
そんな感じの、いろんなことを示唆的に教えてくれるようなツール/パートナーとして、オブザーバビリティツールを多くの人に活用していってもらいたいものです。

Discussion