ByteScope

logcat

端末を変える

システムログを流し読みします。端末で起きていることすべての実況です。

コマンド
adb shell logcat
コマンド
システムとログ
リスク
端末を変える

構文

logcat [-v <format>]

フラグと引数

トークン意味
-v <format>行の形式を選びます。持つ価値があるのは `threadtime`(日付、時刻、pid、tid、レベル、tag)で、`brief` はより簡潔な `I/Tag( 1234):` の形です。
-b <buffer>どのリングバッファを読むか。`default` は main、system、crash をまとめて覆い、`all` は shell が開けるものすべてを取ります。このビルドが知らない名前は、無視されるのではなく名指しで断られます。
-d流し読みせず、いまバッファにあるものを吐いて終了します。ストリームにはない境界で、自動化するものの正しい既定です。
-t <count>最後の N 行を印字して終了します。`-d` を含意します。バッファが満杯の端末では全部を吐くより安く、何かが起きた後に前後関係を掴む実用的な方法です。
-m <count>N 行印字したら止まります。`-t` とは併用できません。あちらは天井ではなく始点を決めるものだからです。コマンドはそう言って、どちらの意味かを推測せずに終了します。
-cバッファを消します。破壊的で、しかも権限は要りません。行は消え、端末に控えは残らず、コマンドは尋ねません。
-G <size>バッファの大きさを変えます。数値のあとに乗数を付けて書き、裸の数値は断られます。新しい大きさはケーブルを抜いても残るので、このページでいちばん長生きするものです。

使用例

  • logcat -v threadtime

    全フィールドが揃った形式で、ビューアが解析すべきものです。

  • logcat -v brief

    古い簡潔な形。貼り付けられたログではいまも見かけます。

  • logcat -t 200 -v threadtime

    最後の 200 行を全フィールド付きで出して終了します。止め方を考えなければならないストリームを開く前に試すべき、境界のある形です。

  • logcat -b crash -d -v threadtime

    crash のバッファだけを 1 回吐きます。アプリを殺した fatal な例外が記録される場所を、周りの何千行も抜きで見られます。

出力の読み方

出力例

07-26 13:37:01.234  1234  1250 I ActivityManager: Start proc 3062:com.example/u0a234
07-26 13:37:02.010  3062  3062 E MyApp   : java.lang.IllegalStateException: not attached

`threadtime` なら日付、時刻、プロセス id、スレッド id、1 文字のレベル、tag、そしてコロンと空白のあとにメッセージです。tag はそのコロンまで空白を含み得ます。すべての行がログレコードとは限りません。`--------- beginning of main` や空行はログ自身のバナーなので、解析しようとせず表示してください。

出力フィールド

フィールド意味
MM-DD HH:MM:SS.mmm端末自身のローカル時刻。タイムゾーンは印字されません。
pid tidプロセス id とスレッド id。同じ数値ならメインスレッドです。
V D I W E FVerbose、Debug、Info、Warn、Error、Fatal の順に深刻度が上がります。
tag書いた側が選んだ文字列。ログを絞り込む実用的な手段です。
--------- beginning of …バッファの境界で、レコードではありません。
--------- switch to …同じバナーのもう 1 つの形で、既に始まっているバッファから後の行が来たときに印字されます。複数のバッファを同時に読むとき、この 2 つが出どころの変わった地点をすべて印します。

必要な権限

root も `adb root` も、USB デバッグを超えて開発者向けオプションで入れるものも要りません。そしてこのリファレンスの大半と違い、それは既定の結果ではなく意図した付与です。`adbd` は権限を落とす前に `shell` ユーザーへ渡す補助グループの一覧に `AID_LOG` を入れます。Jelly Bean 以来アプリが自分の行しか読めないのに、ケーブルがすべてのアプリの行を読めるのはそれがあるからです。コマンド自身のヘルプも、root と log と system のユーザーだけが他の uid のログを見られると、反対側から同じことを言っています。その付与はすべてを覆うわけではありません。`security` のバッファは shell 向けには開かれず、しかも名指しで頼んだときだけは、黙って飛ばすのではなく拒否を報告する唯一のバッファです。読むことに権限は要りませんが、このコマンドができることのうち 3 つは読み取り専用ではなく、どんな書き込みとも同じ注意に値します。バッファの消去は、1 分後に欲しくなる証拠を壊します。サイズ変更はケーブルを抜いた後も残ります。ファイルへの書き出しは端末自身のストレージにバイトを置きます。3 つとも root は要らないので、集めるために接続したログを紛れ込んだフラグ 1 つが捨てるのを止めるものは、注意のほかにありません。Android Logcat Viewer はそのどれも使わずに流し読みし、絞り込みはブラウザ側でやるので、バッファは見つけたときのまま残ります。

エラーメッセージの読み解き

メッセージ意味
logcat: Unexpected EOF!読み手が書き手に追いつけなかったか、ロギングのデーモンが消えました。メッセージはさらに数行続き、2 つの原因と対処(バッファを大きくする)を名指しします。忙しい端末ではクラッシュではなくスループットの問題だからです。このストリームを消費するものは追いつくか、頼む量に境界を付けるかのどちらかで、3 つめの選択肢はありません。
logcat: Unable to open log device 'security'.そのバッファは存在しますが shell からは読めません。しかもこれは、使えないことが報告される唯一のバッファです。暗黙に選ばれて存在しないバッファは黙って飛ばされ、自分で名前を渡したときだけこの行が出ます。要求の残りの部分には影響しません。
logcat: Failed to wait for logd.ready to become true. logd not running?ロギングのデーモンが、尋ねられてから 1 秒のうちに自分を公開しませんでした。起動の早い時期と、デーモンを再起動した後には想定内です。ログ自体が失われたわけではなく、端末の起動が終わってからもう一度尋ねるのが対処のすべてです。
logcat: Unknown buffer 'radio1' listed for -b.そのバッファ名はこのビルドが知るものではありません。使える組はリリースやベンダーで固定ではないので、他の端末から一覧を持ち込まず `logcat --help` で端末に尋ねてください。そしてこのコマンドは、認識できたバッファを読むのではなく呼び出し全体を断ります。
logcat: Invalid filter expression in logcat args.tag とレベルのフィルタ式が解析できませんでした。レベルは 1 文字、tag はコロンで終わるので、コロンを含む tag はこの方法ではまったく絞り込めず、行が届いた後に照合するしかありません。何も読まれておらず、バッファを開く前に終了します。

何が変わるか、そして戻る道

ログを読むだけなら何も変わりませんが、2 つのフラグは変えます。`-c` はバッファを消去し、その行は失われて端末には控えも残りません。`-G <サイズ>` はバッファのサイズを変え、この設定はケーブルを抜いても残ります。どちらもコマンドでは元に戻せません。`-G` は元のサイズを書き戻すしかないので変更前に控えておき、`-c` は消す前に `-d` で保存してください。素の `logcat`、`-d`、`-t`、`-v` は読み取り専用です。

バージョンとメーカーに関する注意

  • 何かが止めるまで流れ続け、忙しい端末では毎分数千行になります。これを消費する側には上限が必要で、なければ機械が音を上げるまで増え続けます。
  • 長い行は転送の途中で半分に切られ得るので、読む側はチャンクの境界をまたいで部分行を保持しなければ、100 行に 1 行くらい壊します。
  • どのバッファがあるか、このビルドがどのフィルタ式を理解するかは変わります。仮定せず `logcat --help` で端末に尋ねてください。
  • 他のアプリの行を読めるのは、`adbd` が権限を落とす前に shell へ `log` グループを与えているからです。要求する実行時の権限はなく、`adb root` も要りません。そしてそれは、アプリがケーブルの見るものを再現できない理由でもあります。
  • 消去、サイズ変更、ファイルへの書き出しは、読むためのコマンドのページに隠れた書き込みで、どれも先に尋ねません。始まった途端に終わるストリームは、端末を責める前に紛れ込んだ消去のフラグを疑う価値があります。

これには UI があります

Android Logcat Viewer はこのコマンドを USB 経由で実行し、返ってきたものを解析します。Chromium 系ブラウザだけで、SDK も不要、どこにもアップロードしません。

Android Logcat Viewer を開く

関連コマンド

logcat と同じ作業で出てくるコマンド。

コマンド何をするか
dumpsys dropboxクラッシュ、ANR、tombstone を保持するプラットフォームのリングバッファ。root なしで ANR トレースを読む方法です。
dumpsys activity activitiesいまどのアプリが前面にいるか、そしてその背後のタスクとスタックの構造。
run-asあるアプリ自身の uid でコマンドを実行します。root なしで debuggable ビルドのプライベートファイルを読む方法です。

他のシステムとログコマンド

コマンド何をするか
top1 回分のプロセス表:CPU 使用率、メモリ、状態、コマンドライン。
getpropシステムプロパティを表示します。端末自身が語る「これは何か」です。

Web ADB ツール群のパーサを書きながら、AOSP・toybox・カーネルのソースに突き合わせて確認しています。バージョンやメーカーで本当に挙動が変わるところは、世界の半分の端末で間違いになる数値を出す代わりに、そう書いてあります。

よくある質問

adb shell のコマンドはどう実行しますか?

端末で開発者向けオプションと USB デバッグを有効にし、ケーブルを繋いだうえで、platform-tools を入れた機械から adb shell <コマンド> を実行します。adb shell だけを実行すれば対話プロンプトが出て、接頭辞なしで打てます。スクリーンショットのようにバイナリを出力するコマンドでは adb shell ではなく adb exec-out を使ってください。素のシェルサービスは端末を割り当て、それが改行のバイトを書き換えてデータを壊します。

adb shell のコマンドに root は必要ですか?

このリファレンスにあるものには不要です。すべて shell ユーザーとして動き、自分の Android ユーザー向けのパッケージ管理、ほとんどの dumpsys サービスの読み取り、設定プロバイダへの書き込み、入力の注入、共有ストレージの読み取りができます。root が必要なのはこのリファレンスがあえて避けていること、つまり他のアプリのプライベートデータの読み取り(debuggable なビルドに対する run-as を除く)、システムパーティションへの書き込み、/data/anr の直接読み取りです。

自分の端末では出力が違って見えるのはなぜ?

Android のバージョンか、メーカーのどちらかです。一部のフラグやフィールドは特定のリリースから入ったもので、それはコマンドごとに注記しています。残りはメーカーによる改変で、いちばん影響が大きいのは dumpsys です。ダンプはデバッグ出力で、そのテキストはサービスの作者が最後に印字した内容そのもの、しかもメーカーはそれを変えて自分の変更をバックポートします。フィールドは位置ではなく名前で読み、見慣れない形は失敗ではなく差分として扱ってください。

端末ではなくブラウザから実行できますか?

多くのコマンドは可能です。このサイトの Web ADB ツール群は、Chromium 系のデスクトップブラウザから WebUSB で端末と話し、SDK のインストールも不要、どこにもアップロードしません。各ページは、該当するツールがあればそこへリンクしています。知っておく価値のある制限が 2 つあります。ADB インターフェイスを保持できるプログラムは同時に 1 つだけなので、デスクトップの adb server は先に止める必要があります。そして adb forward と adb reverse はブラウザでは一切動きません。

打つより押したい場合は、Web ADB Toolkit がこの種のコマンドをブラウザから USB 経由で実行します。あるいは全コマンドを見る。