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 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(„message”), библиотека итеративно преноси поруку свим дрвећима редом садње. Свако дрво може да филтрира поруку по нивоу, tag-у или садржају и обради је на свој начин.

Редослед садње је важан: прво посађено дрво се обрађује прво. Препоручује се садња DebugTree-ја као последњег, да би прилагођена дрвећа (нпр. Crashlytics) обрадила поруку пре него што стигне у Logcat.

Безбедност нити

Timber је безбедан за нити — сви методи су синхронизовани кроз интерни 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. године. Саветоваћемо вас и предложити најбоље решење.

Разговарајте о пројекту

Прочитајте такође