Логирование с помощью logcat

Рейтинг: 61% · 6 голосов
Полный курс по Android Debug Bridge: установка, подключение, shell, логи, dumpsys, автоматизация, root, беспроводная отладка. Уроки по главам с обсуждением.
Ответить
Аватара пользователя
android_roman
Сообщения: 45
Зарегистрирован: 11 май 2026, 05:31

Логирование с помощью logcat

Сообщение android_roman »

АкадемияADB: Android Debug BridgeГлава 8 из 29
Оглавление курса (29)
  1. Введение в Android Debug Bridge
  2. Установка и настройка рабочей среды
  3. Подключение устройства (проводное и беспроводное)
  4. Базовые команды ADB и управление сервером
  5. Команды состояния и перезагрузки
  6. Навигация по файловой системе
  7. Управление пакетами приложений
  8. Логирование с помощью logcat (вы здесь)
  9. Системные дампы и диагностика (dumpsys)
  10. Анализ производительности в реальном времени
  11. Эмуляция ввода (input)
  12. Управление Activity и Intent (am)
  13. Работа с оконным менеджером (wm)
  14. Захват экрана и запись видео
  15. Root-доступ и его применение
  16. Модификация системных настроек через settings
  17. Команды для поставщиков контента (content)
  18. Резервное копирование и восстановление (backup)
  19. Проброс портов и туннелирование
  20. Беспроводная отладка (Wi-Fi)
  21. Взаимодействие с эмуляторами
  22. Написание скриптов на Bash/CMD/PowerShell
  23. ADB в языках программирования
  24. Автоматизация тестирования с ADB
  25. Безопасность и лучшие практики
  26. ADB на Android TV, Wear OS и IoT
  27. Восстановление и низкоуровневые операции
  28. Расширенные возможности оболочки и инструменты
  29. Отладка самого ADB и устранение неполадок
Logcat открываешь первым, когда приложение падает, тормозит или молча делает не то. В главах 4 и 5 мы разобрались с сервером ADB и базовыми командами, теперь переходим к диагностике. Всё, что происходит на устройстве, от старта процессов до падений со stack trace, стекается в логи, и adb logcat даёт к ним доступ без root.

Как устроено логирование и какие бывают буферы:

Начиная с 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
Есть ещё буферы security и stats, но первый недоступен через adb, а второй служит для статистики платформы, в ручной отладке они не участвуют.

Размеры буферов:

Код: Выделить всё

adb logcat -g
Типичный вывод на Android 15:

Код: Выделить всё

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
Буферы кольцевые: когда место кончается, старые записи затираются новыми. На живом устройстве main забивается за считанные минуты, поэтому лог пишут в файл сразу, а не вспоминают о нём после воспроизведения бага. Увеличить буфер можно в настройках разработчика (пункт про размер буфера журнала, до 16 МБ) или командой

Код: Выделить всё

adb logcat -G 16M
, но на части прошивок -G срабатывает только с root, через меню надёжнее.

Базовое чтение и сброс:

Код: Выделить всё

adb logcat
Поток идёт непрерывно, выход по Ctrl+C. Если устройств подключено несколько, ADB ответит error: more than one device/emulator, укажите серийник:

Код: Выделить всё

adb -s R58M42ABCDE logcat
.

Режимы без бесконечного потока:

Код: Выделить всё

adb logcat -d
adb logcat -t 300
adb logcat -T "06-12 14:00:00.000"
-d печатает накопленное и выходит, -t 300 выводит последние 300 строк и тоже выходит, -T показывает записи с указанного момента и продолжает слушать.

Сброс буферов:

Код: Выделить всё

adb logcat -c
adb logcat -b all -c
Первый вариант чистит только дефолтную связку main, system, crash. events и radio останутся как были, и это классическая ловушка: почистил, а старые события всё равно лезут в вывод. Перед воспроизведением бага делайте -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"
Покажет Info и выше от ActivityManager, Debug и выше от MyApp, остальное заглушит. Без "*:S" в конце фильтр почти бесполезен: незатронутые теги продолжат сыпаться. Это ошибка номер один у новичков. Кавычки вокруг *:S нужны, чтобы шелл (особенно zsh на macOS) не раскрыл звёздочку как маску файлов.

Сокращение для одного тега:

Код: Выделить всё

adb logcat -s OkHttp
Флаг -s эквивалентен *:S, команда выше показывает только OkHttp всех приоритетов. Глобальный срез по приоритету:

Код: Выделить всё

adb logcat "*:E"
Только Error и Fatal от всех. Постоянный фильтр удобно зашить в переменную окружения, клиент adb подхватит её сам:

Код: Выделить всё

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
К формату через запятую добавляются модификаторы: color раскрашивает строки по приоритету, year дописывает год, UTC и zone управляют часовым поясом, epoch печатает unix-время, uid добавляет колонку с UID процесса.

Код: Выделить всё

adb logcat -v threadtime,color
adb logcat -v time,year,zone
adb logcat -v uid
color работает в терминалах с поддержкой ANSI: Linux и macOS из коробки, на Windows это Windows Terminal или PowerShell 7. В классическом cmd по умолчанию вместо цвета увидите мусор из escape-последовательностей вида [0;32m.

Фильтрация по PID и UID:

Тег режет по подсистеме, но приложение пишет под десятками тегов. Надёжнее фильтровать по процессу:

Код: Выделить всё

adb shell pidof -s com.example.app
12345
adb logcat --pid=12345
Одной строкой в bash/zsh:

Код: Выделить всё

adb logcat --pid=$(adb shell pidof -s com.example.app)
Минус: после краша или перезапуска PID меняется и фильтр умирает вместе с процессом. Для долгих сессий лучше --uid, он переживает рестарты:

Код: Выделить всё

adb shell pm list packages -U | grep com.example.app
package:com.example.app uid:10145

adb logcat --uid=10145
Чтение чужих UID требует привилегий, но пользователь shell, от имени которого работает adb, состоит в группе log, поэтому на обычном нерутованном устройстве через adb это работает.

grep и регулярные выражения:

Классика конвейеров:

Код: Выделить всё

adb logcat -d | grep -i "exception"
adb logcat | grep -E "FATAL|AndroidRuntime"
На Windows в cmd grep нет, замена встроенная:

Код: Выделить всё

adb logcat -d | findstr /i exception
, а в PowerShell

Код: Выделить всё

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
-m 20 завершает logcat после 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
am_proc_start и am_proc_died показывают жизнь процессов, am_anr фиксирует ANR с причиной, am_low_memory сигналит, что система начала убивать фоновые процессы. Когда тестировщик пишет "приложение само закрылось", именно events отвечает, убила его система по памяти или оно упало само. Модификатор descriptive подставляет к полям их смысл:

Код: Выделить всё

adb logcat -b events -v descriptive
Сохранение логов в файл:

Самый ходовой приём, дамп истории в файл на компьютере:

Код: Выделить всё

adb logcat -d -v threadtime,year > bug_2026-06-12.txt
adb logcat -v threadtime | tee live.log
tee пишет в файл и параллельно показывает на экран. В PowerShell 5.x есть ловушка: перенаправление > сохранит файл в UTF-16, и сторонние анализаторы подавятся. Либо работайте из cmd, либо ставьте PowerShell 7.

Можно писать лог в файл прямо на устройстве, с ротацией:

Код: Выделить всё

adb shell logcat -f /data/local/tmp/app.log -r 1024 -n 8 "*:W"
-r 1024 ротирует файл каждые 1024 КБ, -n 8 хранит восемь файлов. Процесс живёт, пока открыта shell-сессия adb. Забрать результат:

Код: Выделить всё

adb pull /data/local/tmp/app.log .
Анализ в Android Studio:

Сохранённые дампы чаще всего разбирают редактором и grep, а вот живой поток удобнее смотреть в панели Logcat в Android Studio. Начиная с версии Dolphin там язык запросов вместо старых выпадающих фильтров:

Код: Выделить всё

package:mine level:error
package:com.example.app tag:OkHttp message~:timeout.*504
-tag:Choreographer level:warn age:30m
package:mine ограничивает вывод приложениями открытого проекта, message~: принимает регулярку, минус перед ключом инвертирует условие, age: отсекает старые записи. Ключи и значения подсказываются автодополнением, запросы комбинируются пробелами и применяются на лету. Под капотом это тот же adb logcat, так что всё из этой главы остаётся актуальным и без IDE.

Частые грабли, коротко:

Фильтр tag:priority без "*:S" в хвосте не глушит остальное. logcat -c не трогает events и radio, чистите -b all -c. При двух подключённых устройствах любая команда падает, пока не укажете adb -s. Если в потоке появилось read: unexpected EOF!, читатель не успевает за записью или буфер сбросили во время чтения, перезапустите logcat с более узким фильтром или увеличьте буфер. И не ловите баг на буфере по умолчанию: к моменту, когда вы его заметили, main мог уже дважды перезаписаться.

В следующей главе займёмся dumpsys: если logcat показывает, что происходило, то dumpsys показывает, в каком состоянии система находится прямо сейчас.
👍6 ❤️1 🔥 😄 🤔1
✔ Лучший ответ сформирован автоматически — linux4
android_roman писал(а):Первый вариант чистит только дефолтную связку main, system, crash. вот этого мне не хватало месяц назад. дебажил утечку процессов, сделал logcat -c, а в events продолжали висеть старые am_proc_died, два часа гонялся за призраками. теперь только -b all -c, спасибо что прямо проговорили
Перейти к ответу →
Аватара пользователя
linux4
Сообщения: 2
Зарегистрирован: 17 май 2026, 19:42

Re: Логирование с помощью logcat

Сообщение linux4 »

✔ Лучший ответ — сформирован автоматически
android_roman писал(а):Первый вариант чистит только дефолтную связку main, system, crash.
вот этого мне не хватало месяц назад. дебажил утечку процессов, сделал logcat -c, а в events продолжали висеть старые am_proc_died, два часа гонялся за призраками. теперь только -b all -c, спасибо что прямо проговорили
👍1 ❤️ 🔥 😄 🤔
Аватара пользователя
robdon
Сообщения: 2
Зарегистрирован: 12 май 2026, 09:47

Re: Логирование с помощью logcat

Сообщение robdon »

а если телефон сам перезагрузился и баг был до ребута? буферы же в памяти logd, после перезагрузки там пусто. слышал что есть logcat -L который вытаскивает лог прошлой загрузки из pstore, но у меня на одном устройстве работает, на другом пусто. от чего это зависит, от прошивки?
👍1 ❤️ 🔥1 😄 🤔
Аватара пользователя
gw0557
Сообщения: 1
Зарегистрирован: 27 май 2026, 19:32

Re: Логирование с помощью logcat

Сообщение gw0557 »

добавлю по конвейерам: если строите цепочку adb logcat | grep ERROR | tee err.log, ставьте grep --line-buffered. без него grep копит вывод блоками по 4кб и строки в tee приходят пачками с задержкой, на живом мониторинге это очень сбивает, кажется что лог замер
👍1 ❤️ 🔥 😄 🤔1
Аватара пользователя
pandas_coder
Сообщения: 2
Зарегистрирован: 23 май 2026, 18:36

Re: Логирование с помощью logcat

Сообщение pandas_coder »

вопрос по --pid. у нас приложение мультипроцессное, есть :remote и :push процессы. pidof -s вернет только один pid, и --pid покажет только главный процесс. получается для таких случаев только --uid и остается? или можно как-то несколько pid перечислить?
👍1 ❤️1 🔥 😄 🤔
Ответить
← Предыдущая глава
Управление пакетами приложений
Следующая глава →
Системные дампы и диагностика (dumpsys)

Все главы курса «ADB: Android Debug Bridge»

Поделиться темой: ✈ Telegram VK
  • Похожие темы

Вернуться в «ADB: Android Debug Bridge»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость