RevCommモバイルアプリチームの横内です。本日はRevCommアドベントカレンダー12日目として、私たちがモバイルアプリチームとして実行しているログ戦略についてご紹介します。
私たちはMiiTel RecPodやMiiTel Phone Mobileなどのアプリを開発/運用しております。このようなtoBアプリにおいて、ログは単なるエラー検知以上の役割を持ちます。
特に重要なのは「特定顧客の特定事象の再現性確保」です。お客様から問題報告があった際、ログがなければ再現調査に多大な時間を要します。
本記事では、この再現性確保を目的としてDatadog RUM, SDKの機能とloggerパッケージを用いた実践的なFlutterアプリのデータ収集・分析について解説します。
環境に応じたログレベル制御と本番データの最適化
ログの検索効率とデータ量を最適化するため、環境に応じてログレベルを制御しています。
- ログレベルの切り替え: 開発環境では
Debugレベルまでのログを許可し、本番環境ではInfoレベル以上のログのみを許可しています。 - 制御方法: この切り替えは、
--dart-defineを利用したビルド時の制御によって行っています。 Infoログの配置: 本番環境で有効なInfoレベルのログは、処理の起点を示す目的でViewModelやUseCaseなどの処理層の開始時に限定して配置しています。UI層やRepository層には原則配置しません。本番環境ではログが少ないほうが検索効率が上がるので、必要最低限のログにとどめています。
loggerパッケージによるデータ収集と制御の構造
私たちが作っているモバイルアプリではログの記述にはloggerパッケージを使用し、その出力をDatadog SDKにcustomアクションとして送信することで追跡可能なロギングを実現しています。
class AppLogger extends Logger { ... @override void i( dynamic message, { DateTime? time, Object? error, StackTrace? stackTrace, }){ ... super.i(message, time: time, error: error, stackTrace: stackTrace); stackTrace ??= Trace.current(1).terse; // customアクションのコード例 DatadogSdk.instance.rum?.addAction( RumActionType.custom, name: message.toString(), attributes: { 'level': 'Info', 'stackTrace': stackTrace.toString(), } ); ... } }
メタデータのグローバル付与
ログメッセージ内に手動で追跡用IDを埋め込むと、付与漏れや誤った情報が記録されるリスクがあります。Datadog SDKの機能には、すべてのログとRUMイベントに追跡用IDを自動で付与する仕組みがあります。
ユーザーがログインした際などにsetUserInfo / addUserExtraInfoを呼び出すと、ユーザーIDやセッションIDなどの基本的な情報やテナントのIDといったカスタム属性がその後のすべてのログおよびRUMイベントに付与することができます
Datadog RUMによる「ユーザー操作の自動キャプチャ」
Flutterアプリケーションにおけるユーザーの操作と画面のコンテキストを効果的に収集するため、Datadog RUM (Real User Monitoring) SDKの自動トラッキング機能を活用しています。 これにより、エラー発生時の状況把握を迅速化し、再現調査の負担軽減を目指しています。
導入方法は以下を参考にしてください
https://docs.datadoghq.com/ja/real_user_monitoring/application_monitoring/flutter/setup
DatadogNavigationObserverによる画面遷移の自動追跡
エラーログを調査する際、ユーザーが「どの画面で」「どれくらいの時間操作していたか」という情報(View Event)は不可欠なコンテキストです。私たちは、この画面のコンテキストを自動で記録するために、Datadog SDKが提供するDatadogNavigationObserverを使用しています。
MaterialApp(
home: HomeScreen(),
navigatorObservers: [
DatadogNavigationObserver(DatadogSdk.instance),
],
);
この設定により、Datadog上でクラッシュやエラーが発生した直前のView Eventが明確に紐づけられ、再現調査に必要な画面のコンテキストを容易に把握できます。
RumUserActionDetectorとSemanticsによる操作アクションの記録
画面のコンテキストだけでなく、「ユーザーが何をしたか」というアクション(タップ、ジェスチャー)の記録も再現性には重要です。私たちは、RumUserActionDetectorとFlutterのSemanticsを組み合わせて、この操作アクションの記録を実現しています。
アプリの一番上の階層のウィジェットをRumUserActionDetectorでラップすることで、タップやスクロールといったユーザーのジェスチャーが自動的にキャプチャされ、RUM Action EventとしてDatadogに送信されます。これにより、アクションログの記録漏れを防ぎ、再現時の操作手順を後から辿りやすくしています。
RumUserActionDetector(
rum: DatadogSdk.instance.rum,
child: Scaffold(
appBar: AppBar(
title: const Text('RUM'),
),
body: // Rest of your application
),
);
Semanticsによるアクション名の明確化
RumUserActionDetectorはTextButtonやListTileなど、テキスト情報を持つウィジェットに対する操作についてはそのテキストをアクション名として自動で記録する機能を持っています。
- IconButtonやFloatingActionButtonなど、アイコンのみで構成されたボタン
- 画像やカスタム描画された装飾的なウィジェット
これらは、RUM上で tap on InkWell(unknown) のように表示され、再現調査のボトルネックとなります。
そこで、名前が自動で付与されないウィジェットに対してFlutterのSemanticsを活用し、意味のある名前を明示的に付与しています。
InkWell(
...
onPressed: onPressed,
child: Semantics(
label: <付与したい名前>,
child: SvgPicture.asset(
...
),
),
),
これにより、RUM上で tap on InkWell(録音) のようにひと目でわかるテキストで表示されます。
まとめ
本記事では、toBアプリにおける再現性確保を目的としたログ戦略について解説しました。
- 環境別ログレベル制御: 本番環境ではInfoレベル以上に制限し、検索効率を最適化
- loggerパッケージとDatadog SDKの連携: ログをカスタムアクションとして送信し、詳細情報を自動付与
- Datadog RUMによる自動トラッキング: 画面遷移と操作アクションを自動記録
- Semanticsによる明確化: アイコンボタンなどに意味のある名前を付与
これらの仕組みにより問題報告時などの状況把握と再現調査を迅速化し、顧客満足度の向上につなげています。