Как устроено логирование и какие бывают буферы:
Начиная с Android 5 логи собирает демон logd. Он держит в памяти несколько кольцевых буферов, каждый под свой тип сообщений:
main, логи приложений, всё что пишется через android.util.Log;
system, сообщения системных компонентов (ActivityManager, WindowManager, PackageManager);
crash, падения приложений, сюда попадают stack trace от AndroidRuntime;
events, бинарные системные события (старт и смерть процессов, ANR, нехватка памяти);
radio, телефония и мобильная сеть: RIL, SIM, регистрация в сети оператора.
По умолчанию adb logcat показывает связку main, system и crash. Остальные подключаются флагом -b:
Код: Выделить всё
adb logcat -b radio
adb logcat -b events
adb logcat -b main,system,crash,events
adb logcat -b allРазмеры буферов:
Код: Выделить всё
adb logcat -gКод: Выделить всё
main: ring buffer is 1MiB (772KiB consumed, 256KiB readable), max entry is 5120B, max payload is 4068B
system: ring buffer is 1MiB (412KiB consumed, 188KiB readable), max entry is 5120B, max payload is 4068B
crash: ring buffer is 256KiB (4KiB consumed, 4KiB readable), max entry is 5120B, max payload is 4068BКод: Выделить всё
adb logcat -G 16MБазовое чтение и сброс:
Код: Выделить всё
adb logcatКод: Выделить всё
adb -s R58M42ABCDE logcatРежимы без бесконечного потока:
Код: Выделить всё
adb logcat -d
adb logcat -t 300
adb logcat -T "06-12 14:00:00.000"Сброс буферов:
Код: Выделить всё
adb logcat -c
adb logcat -b all -cПриоритеты и фильтрация по тегу:
У каждого сообщения есть тег (обычно имя класса или подсистемы) и приоритет. По возрастанию: V (Verbose), D (Debug), I (Info), W (Warning), E (Error), F (Fatal). S (Silent) сам по себе ничего не печатает, им глушат лишнее.
Фильтр пишется как tag:priority и читается "от этого приоритета и выше":
Код: Выделить всё
adb logcat ActivityManager:I MyApp:D "*:S"Сокращение для одного тега:
Код: Выделить всё
adb logcat -s OkHttpКод: Выделить всё
adb logcat "*:E"Код: Выделить всё
export ANDROID_LOG_TAGS="ActivityManager:I MyApp:D *:S"
adb logcatФлаг -v задаёт формат строки, по умолчанию сейчас threadtime: время, PID, TID, приоритет, тег.
Код: Выделить всё
adb logcat -v brief
adb logcat -v process
adb logcat -v tag
adb logcat -v thread
adb logcat -v time
adb logcat -v longКод: Выделить всё
brief: I/ActivityManager( 1567): Start proc 12345:com.example.app/u0a145
process: I( 1567) Start proc 12345:com.example.app/u0a145 (ActivityManager)
tag: I/ActivityManager: Start proc 12345:com.example.app/u0a145
thread: I( 1567: 1789) Start proc 12345:com.example.app/u0a145
time: 06-12 14:21:35.123 I/ActivityManager( 1567): Start proc 12345:com.example.app/u0a145
threadtime: 06-12 14:21:35.123 1567 1789 I ActivityManager: Start proc 12345:com.example.app/u0a145
long: [ 06-12 14:21:35.123 1567: 1789 I/ActivityManager ]
Start proc 12345:com.example.app/u0a145Код: Выделить всё
adb logcat -v threadtime,color
adb logcat -v time,year,zone
adb logcat -v uidФильтрация по PID и UID:
Тег режет по подсистеме, но приложение пишет под десятками тегов. Надёжнее фильтровать по процессу:
Код: Выделить всё
adb shell pidof -s com.example.app
12345
adb logcat --pid=12345Код: Выделить всё
adb logcat --pid=$(adb shell pidof -s com.example.app)Код: Выделить всё
adb shell pm list packages -U | grep com.example.app
package:com.example.app uid:10145
adb logcat --uid=10145grep и регулярные выражения:
Классика конвейеров:
Код: Выделить всё
adb logcat -d | grep -i "exception"
adb logcat | grep -E "FATAL|AndroidRuntime"Код: Выделить всё
adb logcat -d | findstr /i exceptionКод: Выделить всё
adb logcat -d | Select-String -Pattern "exception","fatal"У самого logcat есть встроенный движок регулярок (ECMAScript), фильтрация идёт по тексту сообщения ещё на устройстве, трафик и нагрузка меньше:
Код: Выделить всё
adb logcat -e "timeout|connection reset"
adb logcat -e "HTTP 5[0-9]{2}" -m 20Буфер событий:
events стоит особняком: записи в нём бинарные, с числовыми тегами, расшифровка лежит на устройстве в /system/etc/event-log-tags. Сюда платформа пишет жизненный цикл системы.
Код: Выделить всё
adb logcat -b eventsКод: Выделить всё
06-12 14:30:12.456 1567 1789 I am_proc_start: [0,12345,10145,com.example.app,next-top-activity,{com.example.app/com.example.app.MainActivity}]
06-12 14:31:02.781 1567 1812 I am_anr: [0,12345,com.example.app,952680005,Input dispatching timed out]
06-12 14:31:40.003 1567 1789 I am_proc_died: [0,12345,com.example.app,900,18]
06-12 14:32:10.220 1567 1790 I am_low_memory: 41Код: Выделить всё
adb logcat -b events -v descriptiveСамый ходовой приём, дамп истории в файл на компьютере:
Код: Выделить всё
adb logcat -d -v threadtime,year > bug_2026-06-12.txt
adb logcat -v threadtime | tee live.logМожно писать лог в файл прямо на устройстве, с ротацией:
Код: Выделить всё
adb shell logcat -f /data/local/tmp/app.log -r 1024 -n 8 "*:W"Код: Выделить всё
adb pull /data/local/tmp/app.log .Сохранённые дампы чаще всего разбирают редактором и grep, а вот живой поток удобнее смотреть в панели Logcat в Android Studio. Начиная с версии Dolphin там язык запросов вместо старых выпадающих фильтров:
Код: Выделить всё
package:mine level:error
package:com.example.app tag:OkHttp message~:timeout.*504
-tag:Choreographer level:warn age:30mЧастые грабли, коротко:
Фильтр tag:priority без "*:S" в хвосте не глушит остальное. logcat -c не трогает events и radio, чистите -b all -c. При двух подключённых устройствах любая команда падает, пока не укажете adb -s. Если в потоке появилось read: unexpected EOF!, читатель не успевает за записью или буфер сбросили во время чтения, перезапустите logcat с более узким фильтром или увеличьте буфер. И не ловите баг на буфере по умолчанию: к моменту, когда вы его заметили, main мог уже дважды перезаписаться.
В следующей главе займёмся dumpsys: если logcat показывает, что происходило, то dumpsys показывает, в каком состоянии система находится прямо сейчас.