or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.md

index.mddocs/

0

# Timber

1

2

Timber is a logger with a small, extensible API which provides utility on top of Android's normal Log class. It uses a Tree-based architecture where logging behavior is added through Tree instances that can be planted into the Timber system. The library automatically determines the calling class for log tags and supports string formatting with proper exception handling.

3

4

## Package Information

5

6

- **Package Name**: com.jakewharton.timber:timber

7

- **Package Type**: Android Library (Gradle/Maven)

8

- **Language**: Kotlin

9

- **Installation**: Add `implementation 'com.jakewharton.timber:timber:5.0.1'` to your build.gradle

10

11

## Core Imports

12

13

```kotlin

14

import timber.log.Timber

15

```

16

17

## Basic Usage

18

19

```kotlin

20

import timber.log.Timber

21

22

// In your Application class onCreate()

23

if (BuildConfig.DEBUG) {

24

Timber.plant(Timber.DebugTree())

25

}

26

27

// Throughout your app

28

Timber.d("Debug message")

29

Timber.i("Info message with %s", "formatting")

30

Timber.w(exception, "Warning with exception")

31

Timber.e(exception)

32

```

33

34

## Architecture

35

36

Timber is built around several key components:

37

38

- **Timber Class**: Main static API (Forest companion object) that delegates to planted Tree instances

39

- **Tree Abstract Class**: Base class for logging implementations with all logging methods

40

- **DebugTree**: Concrete implementation that automatically infers tags from calling class

41

- **Tree Management**: Plant/uproot system for adding and removing logging behavior

42

- **Thread-Local Tagging**: Support for one-time custom tags per logging call

43

44

## Capabilities

45

46

### Static Logging Methods

47

48

All logging methods are available as static calls that delegate to all planted Tree instances.

49

50

```kotlin { .api }

51

// Verbose logging

52

fun v(message: String?, vararg args: Any?)

53

fun v(t: Throwable?, message: String?, vararg args: Any?)

54

fun v(t: Throwable?)

55

56

// Debug logging

57

fun d(message: String?, vararg args: Any?)

58

fun d(t: Throwable?, message: String?, vararg args: Any?)

59

fun d(t: Throwable?)

60

61

// Info logging

62

fun i(message: String?, vararg args: Any?)

63

fun i(t: Throwable?, message: String?, vararg args: Any?)

64

fun i(t: Throwable?)

65

66

// Warning logging

67

fun w(message: String?, vararg args: Any?)

68

fun w(t: Throwable?, message: String?, vararg args: Any?)

69

fun w(t: Throwable?)

70

71

// Error logging

72

fun e(message: String?, vararg args: Any?)

73

fun e(t: Throwable?, message: String?, vararg args: Any?)

74

fun e(t: Throwable?)

75

76

// Assert logging

77

fun wtf(message: String?, vararg args: Any?)

78

fun wtf(t: Throwable?, message: String?, vararg args: Any?)

79

fun wtf(t: Throwable?)

80

81

// Generic priority logging

82

fun log(priority: Int, message: String?, vararg args: Any?)

83

fun log(priority: Int, t: Throwable?, message: String?, vararg args: Any?)

84

fun log(priority: Int, t: Throwable?)

85

```

86

87

**Usage Examples:**

88

89

```kotlin

90

import timber.log.Timber

91

92

// Basic logging with string formatting

93

Timber.d("User %s logged in with ID %d", username, userId)

94

95

// Exception logging

96

try {

97

riskyOperation()

98

} catch (e: Exception) {

99

Timber.e(e, "Failed to perform risky operation")

100

// Or just log the exception

101

Timber.e(e)

102

}

103

104

// Different log levels

105

Timber.v("Verbose details")

106

Timber.i("Information message")

107

Timber.w("Warning message")

108

Timber.wtf("What a Terrible Failure!")

109

110

// Custom priority levels

111

Timber.log(Log.DEBUG, "Custom priority debug message")

112

```

113

114

### Tree Management

115

116

Methods for adding and removing logging implementations.

117

118

```kotlin { .api }

119

/**

120

* Add a new logging tree

121

* @param tree Tree instance to add to the forest

122

*/

123

fun plant(tree: Tree)

124

125

/**

126

* Add multiple logging trees

127

* @param trees Vararg array of Tree instances to add

128

*/

129

fun plant(vararg trees: Tree)

130

131

/**

132

* Remove a planted tree

133

* @param tree Tree instance to remove from the forest

134

*/

135

fun uproot(tree: Tree)

136

137

/**

138

* Remove all planted trees

139

*/

140

fun uprootAll()

141

142

/**

143

* Return a copy of all planted trees

144

* @return Unmodifiable list of currently planted trees

145

*/

146

fun forest(): List<Tree>

147

148

/**

149

* Get the number of currently planted trees

150

*/

151

val treeCount: Int

152

```

153

154

**Usage Examples:**

155

156

```kotlin

157

import timber.log.Timber

158

159

// Plant trees for different environments

160

if (BuildConfig.DEBUG) {

161

Timber.plant(Timber.DebugTree())

162

} else {

163

// Plant custom production trees

164

Timber.plant(CrashlyticsTree(), FileLoggingTree())

165

}

166

167

// Remove specific tree

168

val debugTree = Timber.DebugTree()

169

Timber.plant(debugTree)

170

// Later...

171

Timber.uproot(debugTree)

172

173

// Clear all trees

174

Timber.uprootAll()

175

176

// Check planted trees

177

val currentTrees = Timber.forest()

178

val treeCount = Timber.treeCount

179

```

180

181

### Tag Management

182

183

Support for one-time custom tags for specific logging calls.

184

185

```kotlin { .api }

186

/**

187

* Set a one-time tag for use on the next logging call

188

* @param tag Custom tag to use for the next log message

189

* @return Tree instance for method chaining

190

*/

191

fun tag(tag: String): Tree

192

```

193

194

**Usage Examples:**

195

196

```kotlin

197

import timber.log.Timber

198

199

// Use custom tag for specific log message

200

Timber.tag("CUSTOM_TAG").d("Debug message with custom tag")

201

202

// Chain with logging call

203

Timber.tag("NETWORK").i("API request completed")

204

```

205

206

### Utility Methods

207

208

Additional utility methods for accessing Timber as a Tree instance.

209

210

```kotlin { .api }

211

/**

212

* Get Timber's Forest as a Tree instance for dependency injection

213

* @return Tree instance representing all planted trees

214

*/

215

fun asTree(): Tree

216

```

217

218

**Usage Examples:**

219

220

```kotlin

221

import timber.log.Timber

222

223

// Inject Timber as a Tree dependency

224

class ApiClient(private val logger: Tree = Timber.asTree()) {

225

fun makeRequest() {

226

logger.d("Making API request")

227

}

228

}

229

```

230

231

## Tree Abstract Class

232

233

Base class for implementing custom logging behavior.

234

235

```kotlin { .api }

236

abstract class Tree {

237

// All logging methods (same signatures as static methods)

238

open fun v(message: String?, vararg args: Any?)

239

open fun v(t: Throwable?, message: String?, vararg args: Any?)

240

open fun v(t: Throwable?)

241

242

open fun d(message: String?, vararg args: Any?)

243

open fun d(t: Throwable?, message: String?, vararg args: Any?)

244

open fun d(t: Throwable?)

245

246

open fun i(message: String?, vararg args: Any?)

247

open fun i(t: Throwable?, message: String?, vararg args: Any?)

248

open fun i(t: Throwable?)

249

250

open fun w(message: String?, vararg args: Any?)

251

open fun w(t: Throwable?, message: String?, vararg args: Any?)

252

open fun w(t: Throwable?)

253

254

open fun e(message: String?, vararg args: Any?)

255

open fun e(t: Throwable?, message: String?, vararg args: Any?)

256

open fun e(t: Throwable?)

257

258

open fun wtf(message: String?, vararg args: Any?)

259

open fun wtf(t: Throwable?, message: String?, vararg args: Any?)

260

open fun wtf(t: Throwable?)

261

262

open fun log(priority: Int, message: String?, vararg args: Any?)

263

open fun log(priority: Int, t: Throwable?, message: String?, vararg args: Any?)

264

open fun log(priority: Int, t: Throwable?)

265

266

// Protected methods for customization

267

@Deprecated("Use isLoggable(String, int)", ReplaceWith("this.isLoggable(null, priority)"))

268

protected open fun isLoggable(priority: Int): Boolean

269

protected open fun isLoggable(tag: String?, priority: Int): Boolean

270

protected open fun formatMessage(message: String, args: Array<out Any?>): String

271

272

// Abstract method that must be implemented

273

protected abstract fun log(priority: Int, tag: String?, message: String, t: Throwable?)

274

275

// Internal properties

276

internal val explicitTag: ThreadLocal<String>

277

internal open val tag: String?

278

}

279

```

280

281

**Custom Tree Implementation Example:**

282

283

```kotlin

284

import timber.log.Timber

285

import android.util.Log

286

287

class CustomTree : Timber.Tree() {

288

override fun isLoggable(tag: String?, priority: Int): Boolean {

289

// Only log warnings and errors in production

290

return priority >= Log.WARN

291

}

292

293

override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {

294

// Send to custom logging service

295

MyLoggingService.log(priority, tag, message, t)

296

}

297

}

298

299

// Usage

300

Timber.plant(CustomTree())

301

```

302

303

## DebugTree Implementation

304

305

Concrete Tree implementation for debug builds that automatically infers tags.

306

307

```kotlin { .api }

308

open class DebugTree : Tree() {

309

/**

310

* Extract the tag from a stack trace element

311

* @param element Stack trace element to extract tag from

312

* @return Extracted tag name, may be null

313

*/

314

protected open fun createStackElementTag(element: StackTraceElement): String?

315

316

/**

317

* Log implementation that handles long messages and uses Android Log

318

* @param priority Log priority level

319

* @param tag Log tag (may be null)

320

* @param message Formatted log message

321

* @param t Optional throwable

322

*/

323

override fun log(priority: Int, tag: String?, message: String, t: Throwable?)

324

325

companion object {

326

private const val MAX_LOG_LENGTH = 4000

327

private const val MAX_TAG_LENGTH = 23

328

}

329

}

330

```

331

332

**DebugTree Customization Example:**

333

334

```kotlin

335

import timber.log.Timber

336

337

class CustomDebugTree : Timber.DebugTree() {

338

override fun createStackElementTag(element: StackTraceElement): String? {

339

// Include line number in tag

340

return "${super.createStackElementTag(element)}:${element.lineNumber}"

341

}

342

}

343

344

// Usage

345

Timber.plant(CustomDebugTree())

346

```

347

348

## Constants and Priority Levels

349

350

Timber uses Android Log priority constants:

351

352

```kotlin { .api }

353

// Android Log priority constants (from android.util.Log)

354

const val VERBOSE = 2

355

const val DEBUG = 3

356

const val INFO = 4

357

const val WARN = 5

358

const val ERROR = 6

359

const val ASSERT = 7

360

```

361

362

## Error Handling

363

364

Timber handles various error conditions gracefully:

365

366

- **Null messages**: If message is null and no throwable, the log call is swallowed

367

- **Empty messages**: If message is empty, throwable stack trace is used as message

368

- **Unplanted trees**: Calling `uproot()` on a non-planted tree throws `IllegalArgumentException`

369

- **Self-planting**: Attempting to plant Timber into itself throws `IllegalArgumentException`

370

- **Long messages**: DebugTree automatically chunks messages longer than 4000 characters

371

- **Thread safety**: Tree management operations are synchronized for thread safety

372

373

## Common Patterns

374

375

### Application Setup

376

377

```kotlin

378

import timber.log.Timber

379

380

class MyApplication : Application() {

381

override fun onCreate() {

382

super.onCreate()

383

384

if (BuildConfig.DEBUG) {

385

Timber.plant(Timber.DebugTree())

386

} else {

387

// Plant production trees

388

Timber.plant(CrashlyticsTree(), FileLoggingTree())

389

}

390

}

391

}

392

```

393

394

### Activity Logging

395

396

```kotlin

397

import timber.log.Timber

398

399

class MainActivity : AppCompatActivity() {

400

override fun onCreate(savedInstanceState: Bundle?) {

401

super.onCreate(savedInstanceState)

402

Timber.d("MainActivity created")

403

404

try {

405

setupViews()

406

} catch (e: Exception) {

407

Timber.e(e, "Failed to setup views")

408

}

409

}

410

411

private fun setupViews() {

412

Timber.v("Setting up views")

413

// Implementation

414

}

415

}

416

```

417

418

### Network Logging

419

420

```kotlin

421

import timber.log.Timber

422

423

class ApiClient {

424

fun makeRequest(url: String) {

425

Timber.tag("NETWORK").d("Making request to %s", url)

426

427

try {

428

val response = httpClient.get(url)

429

Timber.tag("NETWORK").i("Request successful: %d", response.code)

430

} catch (e: IOException) {

431

Timber.tag("NETWORK").e(e, "Request failed for %s", url)

432

}

433

}

434

}

435

```