В этой статье рассказывается о процессе ведения журналов, включая стандарты ведения журналов, рекомендации по уровням, классы, цели и приближения с несколькими стеками.
Стандарты ведения журналов
В Android используется множество стандартов, которые объединены в logcat, поэтому ведение журналов в этой ОС – сложный процесс. Ниже приведены основные стандарты, которые мы используем.
| Source | Примеры | Рекомендации по уровням стека |
|---|---|---|
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 для разработки ядра.
На трех рисунках ниже показаны уровни ведения журнала в порядке возрастания.
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 | Informational | Информационные сообщения |
| 7 | Отладка | Сообщения уровня отладки |
Рисунок 5. RFC 5424 – раздел 6.2.1.
Ведение журналов приложений
Выборочное ведение журналов выполняется с помощью класса android.util.Log с использованием TAG и Log#isLoggable, как показано ниже:
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; |
|---|
Регистрацию можно удалить для каждого APK-файла с помощью наборов правил ProGuard, используя R8 во время компиляции. В следующем примере удаляются все записи журнала ниже уровня INFO для android.util.Log:
# 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)
Для системных приложений и сервисов доступны следующие классы:
| Класс | Purpose |
|---|---|
android.telephony.Rlog |
Ведение журнала радио |
android.util.Log |
Общие журналы приложений |
android.util.EventLog |
Ведение журнала событий диагностики системного интегратора |
android.util.Slog |
Ведение журналов фреймворка платформы |
Рисунок 6. Доступные классы системных журналов и их назначение.
Хотя в android.util.Log и android.util.Slog используются одинаковые стандарты уровней ведения журнала, Slog – это класс @hide, который может использоваться только платформой. Уровни EventLog сопоставляются с записями в файле event.logtags в /system/etc/event-log-tags.
Ведение журналов нативных приложений
При регистрации событий в C/C++ используется стандарт syslog, где syslog(2) соответствует ядру Linux syslog, которое управляет буфером printk, а 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 |
Библиотека ведения журналов, которая предоставляет интерфейс потока C++ для ведения журналов, аналогичный ведению журналов в стиле Google (glog). libbase можно использовать как во внешних проектах, так и в приложениях, в которых применяется libbase_ndk. |
Рисунок 8. Библиотеки журналов более высокого уровня.
Приближения с несколькими стеками
Из-за различий в детализации и уровне намерений не существует четких или точных соответствий между разными стандартами ведения журналов. Например, уровни java.util.logging.Level и android.util.Log для журналов ошибок не соответствуют друг другу:
| java.util.Logging.Level | android.util.Log |
|---|---|
| КРИТИЧЕСКАЯ | Log.wtf |
| ТЯЖЕЛАЯ | Log.e |
Рисунок 9. Уровень ошибок в стандартном ведении журнала Java и ведении журнала Android.
В таких случаях используйте индивидуальный стандарт, чтобы определить, какой уровень применить.
При разработке системы с несколькими компонентами уровня стека следуйте указаниям на рисунке 1, чтобы определить, какой стандарт использовать для каждого компонента. Пример сообщений для разных уровней приведен на рисунке 2.
Безопасность и конфиденциальность
Не регистрируйте информацию, позволяющую идентифицировать личность. К ним относятся:
- адреса электронной почты;
- Номера телефонов
- Названия
Аналогично, некоторые данные считаются конфиденциальными, даже если они не позволяют идентифицировать личность.
Например, информация о часовом поясе не считается информацией, позволяющей идентифицировать личность, но она позволяет определить приблизительное местоположение пользователя.
Правила ведения журналов и допустимые сведения должны быть рассмотрены в рамках проверки безопасности и конфиденциальности до выпуска.
журналов устройства.
Доступ ко всем журналам устройства, в том числе с помощью android.permission.READ_LOGS, ограничен:
- Если приложение, работающее в фоновом режиме, запрашивает доступ ко всем журналам устройства, запрос автоматически отклоняется, если только приложение:
- Передает системный идентификатор UID.
- Использует встроенный системный процесс (
UID<APP_UID). - Используется часовой пояс
DropBoxManager. - Доступ только к буферу журнала событий.
- Использует
EventLogAPI. - Использует инструментальные тесты.
- Если приложение на переднем плане с
READ_LOGSзапрашивает доступ к журналам устройства, система предлагает пользователю одобрить или отклонить запрос.