Ведение журналов

В этой статье рассказывается о процессе ведения журналов, включая стандарты ведения журналов, рекомендации по уровням, классы, цели и приближения с несколькими стеками.

Стандарты ведения журналов

В 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;

… If (DEBUG) { Log.v("FOO_TAG", "Extra debug logging."); }

Регистрацию можно удалить для каждого 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.
    • Доступ только к буферу журнала событий.
    • Использует EventLog API.
    • Использует инструментальные тесты.
  • Если приложение на переднем плане с READ_LOGS запрашивает доступ к журналам устройства, система предлагает пользователю одобрить или отклонить запрос.