この記事では、ログの規格、レベルのガイドライン、クラス、目的、マルチスタックのおおよその値を含む、ロギングのプロセスについて説明します。
ログの規格
さまざまな規格が使用され logcat で組み合わされているため、Android でのロギングは複雑です。使用される主な規格は、下記のとおりです。
| ソース | 例 | スタックレベルのガイダンス |
|---|---|---|
RFC 5424(syslog 規格) |
Linux カーネル、多くの Unix アプリ | カーネル、システム デーモン |
android.util.Log |
Android フレームワーク + アプリのロギング | Android フレームワークとシステムアプリ |
java.util.logging.Level |
Java での一般的なロギング | システム以外のアプリ |
図 1: ログレベルの規格。
これらの規格はレベル構造が似ていますが、粒度が異なります。規格間での近似値は次のとおりです。
| RFC 5424 のレベル | RFC 5424 の重大度 | RFC 5424 の説明 | android.util.Log | java.util.logging.Level |
|---|---|---|---|---|
| 0 | 緊急 | システムが使用不可 | Log.e / Log.wtf |
SEVERE |
| 1 | アラート | 早急な対応が必要 | Log.e / Log.wtf |
SEVERE |
| 2 | 重大 | 重大な状態 | Log.e / Log.wtf |
SEVERE |
| 3 | エラー | エラー状態 | Log.e |
SEVERE |
| 4 | 警告 | 警告状態 | Log.w |
WARNING |
| 5 | 注意 | 正常だが重大 | Log.w |
WARNING |
| 6 | 情報 | 情報メッセージ | Log.i |
INFO |
| 7 | デバッグ | デバッグレベルのメッセージ | Log.d |
CONFIG、FINE |
| - | - | 詳細なメッセージ | Log.v |
FINER / FINEST |
図 2: syslog、Android、Java のロギングレベル
ログレベルのガイドライン
ログの規格にはそれぞれ既存のガイドラインがあります。カーネル開発には syslog 規格を使用するなど、選択されたログレベルは使用されている適切な規格に準じます。
ログレベルの順序(最小から最大まで)は、以下の 3 つの図のとおりです。
ERROR |
これらのログは常に保持されます。 |
WARN |
これらのログは常に保持されます。 |
INFO |
これらのログは常に保持されます。 |
DEBUG |
これらのログはコンパイルされますが、実行時に削除されます。 |
VERBOSE |
これらのログは、開発中を除き、アプリにコンパイルされることはありません。 |
図 3: android.util.Log
CONFIG |
静的な構成メッセージのメッセージ レベル |
FINE |
トレース情報を提供するメッセージ レベル |
FINER |
詳細なトレース メッセージを示します |
FINEST |
非常に詳細なトレース メッセージを示します |
INFO |
情報メッセージのメッセージ レベル |
SEVERE |
重大な障害を示すメッセージ レベル |
WARNING |
潜在的な問題を示すメッセージ レベル |
図 4: java.util.Logging.Level。
| 0 | 緊急 | システムが使用不可 |
| 1 | アラート | 早急な対応が必要 |
| 2 | 重大 | 重大な状態 |
| 3 | エラー | エラー状態 |
| 4 | 警告 | 警告状態 |
| 5 | 注意 | 正常だが重大な状態 |
| 6 | 情報 | 情報メッセージ |
| 7 | デバッグ | デバッグレベルのメッセージ |
図 5: RFC 5424 - セクション 6.2.1。
アプリのロギング
以下に示すように、選択されたロギングは Log#isLoggable を使用する android.util.Log クラスによって TAG で実行されます。
if (Log.isLoggable("FOO_TAG", Log.VERBOSE)) {
Log.v("FOO_TAG", "Message for logging.");
}
|
|---|
以下に示すように、ログは選択されたレベルのロギングを提供するよう、実行時に調整できます。
adb shell setprop log.tag.FOO_TAG VERBOSE |
|---|
log.tag.* プロパティは再起動時にリセットされます。再起動後も存続する永続的なバリアントもあります。下記をご覧ください。
adb shell setprop persist.log.tag.FOO_TAG VERBOSE |
|---|
Log#isLoggable チェックは、アプリコードにログトレースを残します。以下に示すように、ブール値の DEBUG フラグは false に設定されたコンパイラの最適化を使用してログトレースをバイパスします。
private final static boolean DEBUG = false; |
|---|
ロギングは、コンパイル時に R8 によって ProGuard ルールセットを介して APK ごとに削除できます。次の例では、android.util.Log の INFO レベルより下のロギングをすべて削除します。
# This allows proguard to strip isLoggable() blocks containing only <=INFO log
# code from release builds.
-assumenosideeffects class android.util.Log {
static *** i(...);
static *** d(...);
static *** v(...);
static *** isLoggable(...);
}
-maximumremovedandroidloglevel 4
|
|---|
これは、基盤となるコードは同じと予想されるが、許可されるログレベルが異なる、複数のアプリのビルドタイプ(たとえば、開発ビルドとリリースビルド)を処理する場合に便利です。ビルドタイプとリリースの予想がログ出力にどのように影響するかを決定するには、アプリ(特にシステムアプリ)に対して明確なポリシーを設定して遵守する必要があります。
Android ランタイム(ART)でのシステム ロギング
システムアプリとサービスで利用できるクラスは複数あります。
| クラス | 目的 |
|---|---|
android.telephony.Rlog |
ラジオのロギング |
android.util.Log |
一般的なアプリのロギング |
android.util.EventLog |
システム インテグレータ診断イベントのロギング |
android.util.Slog |
プラットフォーム フレームワークのロギング |
図 6: 利用可能なシステムログのクラスと目的。
android.util.Log と android.util.Slog は同じログレベルの規格を使用しますが、Slog はプラットフォームでのみ使用可能な @hide クラスです。EventLog レベルは、/system/etc/event-log-tags の event.logtags ファイル内のエントリにマッピングされます。
ネイティブ ロギング
C/C++ でのロギングは syslog 規格に準じており、printk バッファを制御する Linux カーネル syslog に対応する syslog(2)や一般的なシステムロガーに対応する syslog(3)があります。Android は、一般的なシステム ロギングに liblog ライブラリを使用しています。
liblog は、次のマクロ形式を使用してサブログ グループのラッパーを提供します。
[Sublog Buffer ID] LOG [Log Level ID] |
たとえば、RLOGD は [Radio log buffer ID] LOG [Debug Level] に対応します。主な liblog ラッパーは次のとおりです。
| ラッパークラス | 関数の例 |
|---|---|
log_main.h |
ALOGV、ALOGW |
log_radio.h |
RLOGD、RLOGE |
log_system.h |
SLOGI、SLOGW |
図 7: liblog のラッパー。
以下に示すように、Android には、liblog の直接使用よりも優先されるロギング用の上位レベルのインターフェースがあります。
| ライブラリ | 使用方法 |
|---|---|
async_safe |
非同期シグナルセーフな環境からのロギング専用のライブラリ |
libbase |
Google スタイル(glog)のロギングと同様に、ロギング用の C++ ストリーム インターフェースを提供するロギング ライブラリ。libbase は両方の外部プロジェクトで使用でき、libbase_ndk を使用するアプで使用できます。 |
図 8: 上位レベルのログライブラリ
マルチスタックのおおよその値
粒度とレベル インテントの違いがあるため、異なるロギング規格に明らかに、または完全に一致するものはありません。たとえば、エラーログの java.util.logging.Level レベルと android.util.Log レベルは 1 対 1 で対応しているわけではありません。
| java.util.Logging.Level | android.util.Log |
|---|---|
| SEVERE | Log.wtf |
| SEVERE | Log.e |
図 9: 標準の Java ロギングと Android ロギングにおけるエラーレベル
このような場合は、個々の規格を使用して、適用するレベルを決定します。
複数のスタックレベルのコンポーネントでシステム開発を行う際は、図 1 に従って、コンポーネントごとに使用する規格を決定します。階層メッセージのおおよその値のガイドについては、図 2 に従ってください。
セキュリティとプライバシー
個人情報(PII)のログは記録しないでください。これには、次のような詳細情報が含まれます。
- メールアドレス
- 電話番号
- 名前
同様に、特定の詳細情報は、明確に個人を特定できない場合でも機密と見なされます。
たとえば、タイムゾーン情報は個人を特定できるとは考えられませんが、ユーザーのおおよその位置情報を示します。
ログのポリシーと許可される詳細情報は、リリース前にセキュリティおよびプライバシーの審査の一環として処理する必要があります。
デバイスログ
すべてのデバイスログへのアクセスは、android.permission.READ_LOGS を使用するものを含め、制限されます。
- バックグラウンドのアプリがすべてのデバイスログへのアクセスをリクエストすると、アプリが次の条件に該当する場合を除き、リクエストは自動的に拒否されます。
- システム UID を共有する。
- ネイティブ システム プロセスを使用する(
UID<APP_UID)。 DropBoxManagerを使用する。- イベントログのバッファにのみアクセスする。
EventLogAPI を使用する。- インストルメンテーション テストを使用する。
- フォアグラウンドのアプリが
READ_LOGSを使用してデバイスログへのアクセスをリクエストすると、システムはユーザーに対し、アクセス リクエストの承認または拒否を求めるプロンプトを表示します。