Log Level — классификация сообщений логирования по степени критичности, позволяющая разработчикам контролировать объём выводимой информации на разных этапах работы приложения. По данным Google Android Developers, 2024, правильный выбор уровня логирования уменьшает объём логов в production на 85–95% и ускоряет диагностику ошибок. Каждый уровень решает свою задачу — от отладки на этапе разработки до мониторинга критических сбоев в продакшене.
Главное
Log Level — это атрибут каждого лог-сообщения, определяющий его важность и срочность обработки. Современные платформы iOS и Android поддерживают единую шкалу из 6–7 уровней: от максимально детального (Verbose/Trace) до критического (Error/Assert). Выбор уровня определяет, будет ли сообщение записано в лог при текущей конфигурации приложения.
Концепция Log Level основана на принципе пирамиды критичности: чем выше уровень, тем меньше сообщений на нём выводится. По данным Semaphore CI, 2024, в production-приложении распределение выглядит так: Info — 60% сообщений, Warn — 25%, Error — 10%, Debug — 5%. Verbose-сообщения должны быть полностью отключены в production.
Каждая платформа реализует Log Level через собственный API. Android использует android.util.Log с методами v(), d(), i(), w(), e(). Apple — OSLog с уровнями default, info, debug, error, fault. Библиотеки вроде Timber и CocoaLumberjack надстраивают дополнительную функциональность поверх этих стандартных API.
По данным Google I/O 2023, неправильный выбор Log Level — причина 40% проблем с производительностью в production. Разработчики оставляют Debug-логи в релизной сборке, что приводит к избыточной записи на диск и ускоренному разряду батареи.
Verbose (TRACE) — самый детальный уровень, предназначенный исключительно для разработки. На этом уровне выводятся все промежуточные вычисления, итерации циклов, результаты каждого шага алгоритма. На Android этому уровню соответствует Log.v(), на iOS — OSLog с типом debug (до iOS 14 использовался os_trace).
Debug — отладочные сообщения, полезные при разработке и тестировании. Содержат информацию о состоянии ключевых объектов, результаты SQL-запросов, параметры API-вызовов. В отличие от Verbose, Debug-сообщения структурированы и семантически значимы. На iOS этому уровню соответствует OSLogType.debug.
Info — информационные сообщения о штатных событиях приложения: инициализация SDK, успешная авторизация, открытие экрана, получение данных с сервера. Info-сообщения не должны содержать персональные данные пользователей и должны быть безопасны для production-анализа. На iOS используется OSLogType.info, на Android — Log.i().
Warn — предупреждения о потенциальных проблемах. Приложение продолжает работать, но ситуация требует внимания: близкий к лимиту размер кэша, устаревшая версия API, медленный сетевой ответ, повторная попытка соединения. На Android — Log.w(), на iOS — OSLogType.default (для предупреждений).
Error — критические ошибки, при которых приложение не может выполнить запрошенную операцию, но продолжает работу: неудачный запрос к API, потеря соединения, ошибка записи в БД, отсутствие разрешений. На iOS для ошибок используется OSLogType.error, на Android — Log.e().
Assert (WTF) — самый высокий уровень, обозначающий ситуацию "этого не может произойти". Используется для логирования багов, которые нарушают фундаментальные инварианты системы. На Android Assert-сообщения не выводятся в release-сборках по умолчанию. На iOS WTF (What a Terrible Failure) обрабатывается через OSLogType.fault.
Android Log API — встроенный механизм логирования из пакета android.util.Log. Предоставляет 6 статических методов: Log.v(), Log.d(), Log.i(), Log.w(), Log.e() и Log.wtf(). Каждый метод принимает tag (строка-идентификатор источника) и msg (текст сообщения).
class UserRepository {
companion object {
private val TAG = "UserRepo"
}
suspend fun loadUser(id: String): User {
Log.d(TAG, "Loading user with id: $id")
return try {
val response = api.fetchUser(id)
Log.i(TAG, "User loaded successfully")
response.toUser()
} catch (e: Exception) {
Log.e(TAG, "Failed to load user: ${e.message}")
throw e
}
}
}
Фильтрация по уровням в Android Logcat осуществляется через ADB: adb logcat *:E покажет только Error-сообщения. В production-сборках все Log.v() и Log.d() вызовы удаляются ProGuard/R8 при включённой минификации. Log.i(), Log.w() и Log.e() остаются, поэтому важно не выводить чувствительные данные через эти методы.
Для кастомной фильтрации в runtime Android предоставляет Log.isLoggable(tag, level) — метод, который проверяет, включён ли указанный уровень для данного tag. Это позволяет динамически включать детальное логирование для конкретного модуля без пересборки приложения.
OSLog — унифицированная система логирования Apple, заменившая deprecated NSLog. OSLog предоставляет 5 уровней: debug, info, default (notice), error и fault. Главное преимущество — структурированное логирование с поддержкой форматированных строк и динамической фильтрацией через консоль.
import OSLog
let logger = Logger(
subsystem: "com.example.app",
category: "network"
)
func fetchData(from url: URL) {
logger.debug("Starting request to \(url.absoluteString)")
do {
let data = try Data(contentsOf: url)
logger.info("Received \(data.count) bytes")
} catch {
logger.error("Request failed: \(error.localizedDescription)")
}
}
Система фильтрации OSLog работает на уровне операционной системы. Debug-сообщения записываются только при подключении отладчика или включении аргумента -com.apple.CoreData.Logging.debug 1. Info-сообщения собираются в памяти устройства (до 512 КБ) и доступны через Console.app. Error и fault записываются постоянно и доступны для сбора через crash-reporting системы.
Важная особенность OSLog: форматированные строки с плейсхолдерами. Вместо интерполяции строк Swift (которая вычисляется всегда, независимо от уровня), OSLog использует os_log формат с %{public}@ и %{private}@ для разграничения чувствительных данных. Private-параметры маскируются в production-логах.
Основное правило — минимальный набор уровней в production: Info, Warn, Error, Assert. Debug и Verbose должны быть отключены. Причина не столько в безопасности, сколько в производительности: каждый лог-вызов занимает процессорное время на форматирование строки, даже если сообщение не выводится.
Критическая оптимизация — никогда не используйте интерполяцию строк в лог-вызовах. Если строка формируется до вызова log(), процессорное время тратится даже при отключённом уровне. Используйте ленивое форматирование через лямбды или guard-условия.
В Android этой цели служит метод Log.isLoggable(), в OSLog — нативная поддержка форматированных строк с плейсхолдерами. Timber для Android решает проблему через timber.log.Tree с проверкой уровня внутри дерева.
Remote Log Level — практика, при которой уровень логирования управляется с сервера через Firebase Remote Config или аналогичный сервис. Если в production возникает сложная ошибка, разработчик может дистанционно включить Debug-логирование для конкретного модуля на устройствах выбранной группы пользователей.
По данным Firebase, 2024, такая практика сокращает время диагностики редких багов на 60% и позволяет получить полную картину проблемы без установки debug-сборки. Главное ограничение — логи включаются только на следующем запуске приложения после получения конфигурации.
BuildConfig.DEBUG на Android и #if DEBUG на Swift — стандартные механизмы условной компиляции, отключающие отладочные уровни в release-сборках. Для чистой архитектуры рекомендуется вынести выбор Log Level в DI-контейнер или фабрику логгеров, чтобы не загромождать бизнес-логику условными директивами.
Первое правило — каждый лог-вызов должен отвечать на вопрос "кто, что, когда". Кто — компонент или модуль (tag на Android, category на iOS). Что — конкретное событие или изменение состояния. Когда — временная метка, проставляемая автоматически системой логирования.
Второе правило — не логируйте чувствительные данные через Info и выше. Пароли, токены, email, номера телефонов, точные геокоординаты — категорически запрещены в любом логе, который попадает в production. При необходимости используйте маскирование: "email: us***@example.com".
Третье правило — уровень Warn — зона ответственности разработчика, Error — команды. Warn означает "здесь потенциальная проблема, следи". Error — "здесь проблема, исправляй". Не используйте Error для ситуаций, которые ожидаемы и обработаны (например, 404 ошибка API).
Четвёртое правило — консистентность. Весь проект должен использовать единые соглашения об именовании tag и категорий. Рекомендуется ClassName.methodName для Android tag и module.subsystem для iOS category. Это позволяет быстро фильтровать логи по компоненту.
Пятое правило — тестируйте логи. В unit-тестах проверяйте, что в определённых сценариях вызывается правильный Log Level. Для этого существуют mock-библиотеки логирования: Mockito для Android, Cuckoo для iOS. Проверка уровней в тестах предотвращает утечку отладочных сообщений в production.
Часто задаваемые вопросы
Ускоренный разряд батареи и избыточная запись на диск. Каждый Debug-лог форматирует строку и записывает данные в буфер. На devices с Flash-памятью это ускоряет износ накопителя. Кроме того, Debug-логи могут содержать чувствительные данные, недоступные для просмотра в production.
Debug — для тела запроса и ответа, заголовков и статус-кода. Info — для факта выполнения запроса (URL, метод, длительность). Error — для неудачных запросов с кодом 4xx/5xx. Никогда не используйте Verbose для сетевых логов в production.
OSLogType.default (уровень notice) — сообщения средней важности, сохраняются в системном логе и видны в Console.app. OSLogType.info — технические сообщения, не сохраняются постоянно, доступны только при активном профилировании через Instruments.
R8/ProGuard удаляет Log.v() и Log.d() при включённой минификации в release-сборке. Log.i(), Log.w(), Log.e() сохраняются. Для полного удаления всех логов требуется кастомное правило -assumenosideeffects class android.util.Log с указанием всех уровней.
Нет — избыточное логирование ухудшает читаемость и производительность. Логируйте вход только в сложных или асинхронных методах. Для синхронных методов достаточно одного лога в точке возврата или ошибки. Используйте Debug-уровень для трассировки вызовов.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также