Понимание ведения журнала

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

Стандарты бревен

Ведение логов в Android затруднено из-за сочетания различных стандартов, объединенных в logcat . Основные используемые стандарты подробно описаны ниже:

Источник Примеры Руководство на уровне стека
RFC 5424 (стандарт syslog ) Ядро Linux, множество приложений Unix Ядро, системные демоны
android.util.Log Android Framework + ведение журнала приложений 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 Информационный Информационные сообщения
7 Отлаживать Сообщения уровня отладки

Рисунок 5: RFC 5424 — Раздел 6.2.1 .

Ведение журнала приложений

Выборочное ведение журнала выполняется с помощью TAG класса android.util.Log с использованием 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)

Существует несколько доступных классов для системных приложений и служб:

Сорт Цель
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) соответствует syslog ядра Linux, управляющему буфером 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.

Безопасность и конфиденциальность

Не регистрируйте персональные данные (PII). К ним относятся следующие сведения:

  • Адреса электронной почты
  • Номера телефонов
  • Имена

Аналогичным образом, некоторые данные считаются конфиденциальными, даже если они не позволяют явно идентифицировать личность.

Например, хотя информация о часовом поясе не считается персонально идентифицируемой, она дает представление о приблизительном местоположении пользователя.

Политика ведения журнала и приемлемые сведения должны быть обработаны в рамках проверки безопасности и конфиденциальности перед выпуском.

Журналы устройства

Доступ ко всем журналам устройства, в том числе с использованием android.permission.READ_LOGS , ограничен:

  • Если приложение в фоновом режиме запрашивает доступ ко всем журналам устройства, запрос автоматически отклоняется, если только приложение:
    • Использует общий системный UID.
    • Использует собственный системный процесс ( UID < APP_UID ).
    • Использует DropBoxManager .
    • Доступ только к буферу журнала событий.
    • Использует API EventLog .
    • Использует инструментальные тесты.
  • Если приложение на переднем плане с READ_LOGS запрашивает доступ к журналам устройства, система предлагает пользователю одобрить или отклонить запрос на доступ.