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, кожен екземпляр визначає, як обробляти лог-повідомлення
  • Посадка дерев — процес реєстрації 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 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

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