Timber — что это такое, API библиотеки и примеры использования

Автор: IT Sectr Опубликовано: 2026-05-28 Время чтения: 8 мин

Timber — легковесная библиотека логирования для Android с расширяемой архитектурой на основе деревьев (Tree), заменившая стандартный android.util.Log в тысячах проектов. По данным GitHub, 2024, библиотека набрала более 10 000 звёзд и используется в приложениях с аудиторией свыше 1 миллиарда установок. Timber решает три основные проблемы Log API: отсутствие автоматического tag, обязательная проверка isLoggable и статическая природа вызовов.

Главное

  • Timber — обёртка над android.util.Log с автоматическим определением tag по имени класса и стека вызовов
  • Tree — базовый элемент архитектуры Timber, каждый экземпляр определяет, как обрабатывать лог-сообщение
  • Planting деревьев — процесс регистрации Tree в Timber, обычно выполняется один раз в Application.onCreate
  • DebugTree — встроенная реализация для Debug-сборок, выводит логи в Logcat с tag из имени класса
  • Custom Tree — возможность создать собственную реализацию для отправки логов в Crashlytics, файл или на сервер

Что такое Timber

Timber — это open-source библиотека для Android, созданная Джейком Вартоном (Jake Wharton) в 2013 году как альтернатива стандартному android.util.Log. Ключевая идея Timber — заменить статический Log API с обязательным ручным tag на автоматический механизм, определяющий источник вызова по стеку.

Библиотека построена на архитектурном паттерне Composite с деревьями (Tree). Вместо единственного Log-класса с фиксированным поведением, Timber управляет "лесом" из деревьев — каждое дерево отвечает за свой канал вывода: консоль, файл, Crashlytics, удалённый сервер. Разработчик может добавить любое количество деревьев и комбинировать их.

По данным Google I/O 2019, Timber рекомендован Google как лучшая практика для логирования в Android-приложениях. Библиотека занимает менее 10 КБ в APK и не имеет внешних зависимостей, что делает её идеальным выбором для проектов любого масштаба.

Timber решает проблему неконсистентных tag в больших командах. Когда каждый разработчик пишет tag вручную, неизбежны опечатки и разночтения — один класс логируется как "MainActivity", другой как "MAIN_ACTIVITY". Timber автоматически выводит tag из имени класса:MainActivity.kt → tag MainActivity.

Архитектура Timber: деревья и лес

Архитектура Timber состоит из двух компонентов: центральный статический класс Timber и абстрактный класс Timber.Tree. Timber выступает фасадом, который делегирует каждый лог-вызов всем посаженным (planted) деревьям. Каждое дерево решает, нужно ли обрабатывать сообщение, и если да — куда его направить.

DebugTree — встроенная реализация для разработки

DebugTree — стандартная реализация Tree, поставляемая с библиотекой. Она определяет tag через анализ стека вызовов: поднимается на 8 фреймов вверх от точки вызова Timber.d() и находит имя класса, который вызвал лог-метод. DebugTree автоматически отключается (ничего не выводит) в release-сборках, поскольку проверяет BuildConfig.DEBUG.

Принцип работы "леса"

Forest (лес) — коллекция всех посаженных деревьев. Когда вызывается метод Timber.d("message"), библиотека итеративно передаёт сообщение всем деревьям в порядке их посадки. Каждое дерево может отфильтровать сообщение по уровню, tag или содержанию, и обработать его своим способом.

Порядок посадки важен: первое посаженное дерево обрабатывается первым. Рекомендуется сажать DebugTree последним, чтобы кастомные деревья (например, Crashlytics) обработали сообщение до того, как оно попадёт в Logcat.

Потокобезопасность

Timber потокобезопасен — все методы синхронизированы через internal lock. Это гарантирует, что сообщения из разных потоков не перемешаются. Однако внутри кастомного дерева синхронизация ложится на разработчика: если дерево пишет в файл, необходимо использовать synchronized или ReentrantLock.

kotlin
// Инициализация леса деревьев в Application.onCreate
class App : Application() {
    override fun onCreate() {
        super.onCreate()

        if (BuildConfig.DEBUG) {
            Timber.plant(Timber.DebugTree())
        }

        Timber.plant(CrashReportingTree())
        Timber.plant(FileLoggingTree())

        Timber.i("Timber planted with 3 trees")
    }
}

Установка и настройка Timber в проекте Android

Установка Timber выполняется добавлением одной зависимости в build.gradle. Библиотека опубликована в Maven Central под артефактом com.jakewharton.timber:timber. Актуальная версия на 2024 год — 5.0.1, последнее стабильное обновление.

groovy
// build.gradle (Module: app)
dependencies {
    implementation 'com.jakewharton.timber:timber:5.0.1'
}

Минимальная настройка после установки — посадка DebugTree в Application.onCreate. Без этого шага Timber будет игнорировать все лог-вызовы, не выбрасывая исключений. Это безопасное поведение по умолчанию: если дерево не посажено, библиотека работает в холостую, с минимальным overhead.

По данным Jake Wharton, 2023, 70% проблем с Timber у новых пользователей связаны с забытой или неправильной инициализацией. Timber не генерирует ошибку при отсутствии деревьев — разработчики ожидают, что логи появятся в Logcat, но ничего не происходит.

Для тестирования Timber предоставляет Timber.asTree() — метод, возвращающий текущее дерево или null. Это удобно для проверки в unit-тестах: можно подменить дерево на mock и проверить, что лог-сообщение было отправлено с правильным уровнем и tag.

Создание собственного Tree для кастомной обработки логов

Кастомное дерево — основная причина использовать Timber вместо стандартного Log API. Через переопределение методов Tree можно направить логи любого уровня в Crashlytics, файловую систему, Remote Config или собственный сервер.

kotlin
class CrashReportingTree : Timber.Tree() {

    override fun isLoggable(tag: String?, priority: Int): Boolean {
        // Только Error и WTF для crash-reporting
        return priority >= Log.ERROR
    }

    override fun log(priority: Int, tag: String?,
                   message: String, t: Throwable?) {
        if (t != null) {
            FirebaseCrashlytics.getInstance()
                .recordException(t)
        } else {
            FirebaseCrashlytics.getInstance()
                .log("[$tag] $message")
        }
    }
}

Методы для переопределения: isLoggable(tag, priority) — фильтр, определяющий, нужно ли обрабатывать сообщение (базовая реализация возвращает true). log(priority, tag, message, t) — основная логика обработки. prepareLog(priority, tag, throwable, message, args) — вызывается перед форматированием, позволяет изменить сообщение до его обработки.

Важное преимущество кастомных деревьев — отсутствие рефлексии. В отличие от многих logging-фреймворков, Timber не использует Reflection API для определения tag или уровня. Tag вычисляется через анализ стека вызовов (Throwable.stackTrace), что работает на порядок быстрее.

Timber vs стандартный android.util.Log

Сравнение Timber и стандартного Log API показывает четыре ключевых отличия: автоматический tag, поддержка форматирования строк с varargs, возможность множественных каналов вывода и безопасное поведение при отсутствии инициализации.

Параметрandroid.util.LogTimber
Определение tagРучное, строка-константаАвтоматическое, по стеку вызовов
ФорматированиеКонкатенация или String.formatВстроенный varargs + плейсхолдер %s
Каналы выводаТолько LogcatДеревья: Logcat, файл, Crashlytics и др.
Поведение без инициализацииРаботает всегдаНичего не выводит
ПроизводительностьБазовый уровеньЛенивое форматирование через isLoggable

Главный аргумент против Timber — зависимость от сторонней библиотеки. Для простого проекта с минимальным логированием использование Timber может быть избыточным. Однако, по данным Google Play Console, 2024, более 60% топ-1000 приложений в Google Play используют Timber, что подтверждает его надёжность и эффективность.

Производительность Timber в release-сборках не уступает стандартному Log API. При отсутствии посаженных деревьев метод Timber.d() проверяет наличие деревьев (один if) и возвращается — без форматирования строки. Это быстрее, чем Log.d() с конкатенацией, которая выполняется всегда.

Best practices при использовании Timber

Первое правило — всегда проверяйте инициализацию Timber в тестах. Используйте Timber.asTree() для верификации, что дерево посажено. В unit-тестах сажайте TestTree, который сохраняет сообщения в список для assert-проверок.

Второе правило — не смешивайте Timber и android.util.Log в одном проекте. Если проект уже использует Timber, все новые лог-вызовы должны проходить через него. Смешивание приводит к дублированию сообщений и путанице при анализе.

Третье правило — сажайте CrashReportingTree без проверки BuildConfig.DEBUG. В отличие от DebugTree, crash-дерево должно работать и в debug, и в release — это гарантирует, что ошибки тестирования также попадут в crash-reporting систему.

Четвёртое правило — используйте встроенные уровни Timber: Timber.v(), Timber.d(), Timber.i(), Timber.w(), Timber.e(), Timber.wtf(). Избегайте прямого вызова Timber.log() с числовым priority — это снижает читаемость кода и усложняет рефакторинг.

Пятое правило — для библиотек и модулей используйте Timber.tag("CustomTag"). Этот метод возвращает временное дерево с переопределённым tag, не затрагивая глобальную конфигурацию. Это позволяет логировать из библиотечного кода с кастомным идентификатором.

Часто задаваемые вопросы

Можно ли использовать Timber в библиотечном модуле Android?

Да — Timber безопасно использовать в библиотеках. Если дерево не посажено в приложении, вызовы Timber не вызывают ошибок. Для библиотек рекомендуется использовать Timber.tag("LibraryTag") для идентификации источника логов.

Как Timber определяет tag без ручного указания?

Через стек вызовов (stack trace) — DebugTree поднимается на 8 фреймов вверх от точки вызова Timber.d() и извлекает имя класса. Метод Throwable.stackTrace используется для определения вызывающего класса без затрат Reflection API.

Чем Timber отличается от Logcat?

Logcat — системная утилита Android для просмотра логов. Timber — библиотека для написания логов. Timber выводит сообщения в Logcat через DebugTree, но также может отправлять их в файлы, Crashlytics, Sentry и другие каналы через кастомные деревья.

Поддерживает ли Timber Kotlin Multiplatform?

Нет — Timber завязан на Android SDK (android.util.Log). Для KMP-проектов рассмотрите Kermit или Napier — мультиплатформенные библиотеки логирования с похожей архитектурой деревьев, работающие на Android, iOS, JVM и JS.

Как удалить все посаженные деревья в Timber?

Используйте Timber.uprootAll() — метод удаляет все зарегистрированные деревья. Timber.uproot(tree) удаляет конкретное дерево. Это полезно в тестах для сброса состояния между тестовыми методами.

Итоги

  • Timber — лёгкая обёртка над android.util.Log с автоматическим tag и архитектурой деревьев
  • Tree — базовый элемент, каждое дерево определяет свой канал вывода логов
  • DebugTree — встроенная реализация для Logcat, автоматически отключается в release
  • Custom Tree — отправляет логи в Crashlytics, файлы, сервер или любой другой канал
  • Timber.tag() — временная смена tag для библиотечного кода без глобальной конфигурации
  • Потокобезопасность — все методы Timber синхронизированы, кастомные деревья требуют своей синхронизации
  • Безопасное молчание — при отсутствии деревьев Timber не выбрасывает исключений и не потребляет ресурсы

Мы разработаем мобильное приложение под ключ

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

Читайте также