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 — е библиотека с отворен код за Android, създадена от Джейк Уортън (Jake Wharton) през 2013 г. като алтернатива на стандартния android.util.Log. Ключовата идея на Timber — да замени статичния Log API със задължителен ръчен tag с автоматичен механизъм, който определя източника на извикване чрез стека.

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

Според данни от Google I/O 2019, Timber се препоръчва от Google като най-добра практика за логване в Android приложения. Библиотеката заема по-малко от 10 KB в 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(„съобщение”), библиотеката итеративно предава съобщението на всички дървета в реда на засаждане. Всяко дърво може да филтрира съобщението по ниво, tag или съдържание и да го обработи по свой начин.

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

Безопасност на нишките

Timber е безопасен за нишки — всички методи са синхронизирани чрез вътрешно заключване. Това гарантира, че съобщенията от различни нишки няма да се смесят. Вътре в персонализирано дърво обаче синхронизацията е отговорност на разработчика: ако дървото пише във файл, трябва да се използва 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 ще игнорира всички лог извиквания, без да хвърля изключения. Това е безопасно поведение по подразбиране: ако дървото не е засадено, библиотеката работи на празен ход с минимално натоварване.

Според данни от 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 срещу стандартен 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 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също