### Basic Timber DebugTree Setup Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/api-reference/debug-tree.md Demonstrates the essential setup for Timber's DebugTree within an Android application's onCreate method, conditional on build debug status. ```kotlin // In your Application.onCreate() if (BuildConfig.DEBUG) { Timber.plant(Timber.DebugTree()) } ``` -------------------------------- ### Setup Timber in Application Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/INDEX.md Plant a DebugTree for debug builds and a CrashReportingTree for release builds. This is typically done in your Application's onCreate() method. ```kotlin if (BuildConfig.DEBUG) { Timber.plant(Timber.DebugTree()) } else { Timber.plant(CrashReportingTree()) } ``` -------------------------------- ### Create a Custom Logging Tree Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/usage-guide.md Implement a custom Timber.Tree to define your own logging behavior. This example prints logs to the console. ```kotlin class CustomLoggingTree : Timber.Tree() { override fun log(priority: Int, tag: String?, message: String, t: Throwable?) { // Your logging implementation println("[$tag] $message") } } Timber.plant(CustomLoggingTree()) ``` -------------------------------- ### Timber Logging Example Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/INDEX.md Demonstrates the basic usage of Timber for logging messages at different levels. Ensure Timber is initialized and trees are planted before use. ```kotlin Timber.d("message") ``` -------------------------------- ### Environment-Specific Logging Setup Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/configuration.md Set up different logging configurations for development and production environments. This ensures verbose logging during development and more controlled logging in production. ```kotlin object LoggingConfig { fun setupForDevelopment() { Timber.uprootAll() Timber.plant(Timber.DebugTree()) } fun setupForProduction() { Timber.uprootAll() Timber.plant(FilteringTree(Log.INFO, CrashReportingTree())) Timber.plant(FilteringTree(Log.WARN, RemoteLoggingTree())) } fun setupForTesting() { Timber.uprootAll() // No trees planted for testing, or plant a test tree } } // In Application.onCreate() if (BuildConfig.DEBUG) { LoggingConfig.setupForDevelopment() } else { LoggingConfig.setupForProduction() } ``` -------------------------------- ### Using Log Instead of Timber Lint Example Source: https://github.com/jakewharton/timber/blob/trunk/README.md This example demonstrates a Lint warning (LogNotTimber) indicating that the standard Android Log class is being used instead of Timber. ```java Log.d("Greeting", "Hello " + firstName + " " + lastName + "!"); ``` -------------------------------- ### Try-Catch for Planting Custom Trees Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/errors.md This example shows how to use a try-catch block when dynamically planting a custom Timber Tree. It specifically catches IllegalArgumentException, allowing for fallback logging if the tree cannot be planted. ```kotlin import android.util.Log val tree = CustomTree() try { Timber.plant(tree) } catch (e: IllegalArgumentException) { Log.e("App", "Failed to plant tree", e) // Fall back to default logging } ``` -------------------------------- ### Timber Dependency Installation Source: https://github.com/jakewharton/timber/blob/trunk/README.md Add this dependency to your project to use Timber. Ensure you have mavenCentral() configured in your repositories. ```groovy repositories { mavenCentral() } dependencies { implementation 'com.jakewharton.timber:timber:5.0.1' } ``` -------------------------------- ### Timber Message Splitting Example Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/api-reference/debug-tree.md Demonstrates how Timber's DebugTree handles and splits log messages that exceed the maximum log entry length. ```kotlin val tree = Timber.DebugTree() val longMessage = "data=".padEnd(5000, 'x') // Input: "data=xxxxx..." (5000 chars) // Output to Log: // - First call: "data=xxxx..." (4000 chars) // - Second call: "xxxx..." (1000 chars) ``` -------------------------------- ### Timber Utility Methods Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/INDEX.md Provides utility methods for interacting with the Timber forest. Use `asTree()` to get the forest as a `Tree` instance. ```kotlin // Utility Timber.asTree() // Get forest as Tree ``` -------------------------------- ### String.format in Timber Lint Example Source: https://github.com/jakewharton/timber/blob/trunk/README.md This example shows a Lint warning (StringFormatInTimber) for using String.format within a Timber logging call, which Timber handles automatically. ```java Timber.d(String.format("Hello, %s %s", firstName, lastName)); ``` -------------------------------- ### Feature Flag Control for Logging Setup Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/configuration.md Set up logging configurations based on a FeatureFlags object, allowing control over debug logging, crash reporting, and remote logging. ```kotlin fun setupLogging(features: FeatureFlags) { Timber.uprootAll() if (features.debugLogging) { Timber.plant(Timber.DebugTree()) } if (features.crashReporting) { Timber.plant(CrashReportingTree()) } if (features.remoteLogging) { Timber.plant(RemoteLoggingTree(features.remoteEndpoint)) } } ``` -------------------------------- ### Timber Snapshot Dependency Installation Source: https://github.com/jakewharton/timber/blob/trunk/README.md To use a development version of Timber, add this dependency. It requires both mavenCentral() and Sonatype's snapshots repository. ```groovy repositories { mavenCentral() maven { url 'https://central.sonatype.com/repository/maven-snapshots/' } } dependencies { implementation 'com.jakewharton.timber:timber:5.1.0-SNAPSHOT' } ``` -------------------------------- ### Get All Planted Trees Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/api-reference/timber.md Use `forest()` to retrieve a defensive copy of all currently planted `Tree` instances. Modifications to the returned list do not affect the actual forest. ```kotlin fun forest(): List ``` ```kotlin val allTrees = Timber.forest() println("Planted ${allTrees.size} trees") ``` -------------------------------- ### Custom Remote Logging Tree Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/api-reference/tree.md Example of a custom Timber Tree that sends log events asynchronously to an analytics service. ```kotlin class RemoteLoggingTree : Timber.Tree() { override fun log(priority: Int, tag: String?, message: String, t: Throwable?) { val event = LogEvent(System.currentTimeMillis(), priority, tag, message, t) analyticsService.sendAsync(event) } } ``` -------------------------------- ### DebugTree Tag Derivation Example Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/api-reference/debug-tree.md Demonstrates how DebugTree automatically derives tags from the calling class, and how explicit tags set via Timber.tag() are consumed. ```kotlin class MyActivity { fun onCreate() { Timber.d("onCreate called") // Tag: "MyActivity" } fun logWithExplicitTag() { Timber.tag("CustomTag").d("message") // Tag: "CustomTag" Timber.d("next message") // Tag: "MyActivity" (explicit tag consumed) } } ``` -------------------------------- ### Generic Priority Logging Examples Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/api-reference/tree.md Logs a message at an arbitrary priority level using constants from `android.util.Log`. Useful for custom logging levels or when integrating with systems that use different priority schemes. ```kotlin tree.log(Log.INFO, "Generic priority logging") ``` ```kotlin tree.log(Log.ERROR, exception, "An error occurred: %s", errorDesc) ``` -------------------------------- ### Query Planted Trees in Timber Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/usage-guide.md Inspect the currently planted logging trees. You can retrieve all trees, get the total count, or check if any trees are active. ```kotlin // Get all planted trees val trees = Timber.forest() println("${trees.size} trees planted") // Get tree count val count = Timber.treeCount println("Tree count: $count") // Check if any trees planted if (Timber.forest().isEmpty()) { println("No logging trees planted") } ``` -------------------------------- ### Verbose Logging Examples Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/api-reference/tree.md Logs a verbose message. Use for detailed information that may not be needed in production. Supports simple messages, formatted strings, and including exceptions. ```kotlin tree.v("Verbose message") ``` ```kotlin tree.v("User %s logged in", userName) ``` ```kotlin tree.v(exception) ``` ```kotlin tree.v(exception, "Connection failed: %s", errorMessage) ``` -------------------------------- ### Custom Crash Reporting Tree Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/api-reference/tree.md Example of a custom Timber Tree that logs only ERROR and ASSERT priorities to a crash reporting service. ```kotlin class CrashReportingTree : Timber.Tree() { override fun log(priority: Int, tag: String?, message: String, t: Throwable?) { if (priority == Log.ERROR || priority == Log.ASSERT) { CrashReporter.log(message, t) } } } ``` -------------------------------- ### Incorrect Timber String Formatting (Wrong Type) Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/errors.md This example demonstrates a type mismatch between a format specifier and its argument, which can cause runtime exceptions. ```kotlin Timber.d("Success: %b", resultCode) // If resultCode is Int, not Boolean ``` -------------------------------- ### Incorrect Timber String Formatting (Missing Argument) Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/errors.md This example shows a common error where a format specifier is present but no corresponding argument is supplied, leading to a MissingFormatArgumentException. ```kotlin Timber.d("Hello %s %s", name) // Throws MissingFormatArgumentException ``` -------------------------------- ### Get Current Tree Count Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/api-reference/timber.md Access the `treeCount` property to get the number of trees currently planted in the Timber forest. ```kotlin val treeCount: Int ``` ```kotlin println("Tree count: ${Timber.treeCount}") ``` -------------------------------- ### Planting Timber Trees Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/00-START-HERE.md Demonstrates how to initialize Timber by planting custom logging trees. This is the primary way to configure Timber's logging destinations. ```kotlin Timber.plant(Timber.DebugTree()) Timber.plant(CrashReportingTree()) ``` -------------------------------- ### Redundant Exception Message Logging Lint Example Source: https://github.com/jakewharton/timber/blob/trunk/README.md This example shows a Lint warning (TimberExceptionLogging) where an exception's message is explicitly logged alongside the exception itself, which is redundant. ```java Timber.d(e, e.getMessage()); ``` -------------------------------- ### Tag Too Long Lint Example Source: https://github.com/jakewharton/timber/blob/trunk/README.md This example illustrates a Lint error (TimberTagLength) where the logging tag exceeds Android's maximum allowed length of 23 characters. ```java Timber.tag("TagNameThatIsReallyReallyReallyLong").d("Hello %s %s!", firstName, lastName); ``` -------------------------------- ### Plant Multiple Trees for Comprehensive Logging Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/configuration.md This snippet demonstrates planting multiple trees, such as DebugTree, CrashReportingTree, and AnalyticsTree, simultaneously. All trees receive all log calls, allowing for layered logging strategies and comprehensive logging with multiple sinks. ```kotlin Timber.plant( Timber.DebugTree(), CrashReportingTree(), AnalyticsTree() ) ``` -------------------------------- ### String Concatenation in Timber Lint Example Source: https://github.com/jakewharton/timber/blob/trunk/README.md This example highlights a Lint warning (BinaryOperationInTimber) for using string concatenation in a Timber log message, which should be handled by Timber's formatting. ```java Timber.d("Hello " + firstName + " " + lastName + "!"); ``` -------------------------------- ### Incorrect Argument Type Lint Example Source: https://github.com/jakewharton/timber/blob/trunk/README.md This example shows a Lint error (TimberArgTypes) related to providing an argument of the wrong type for a format specifier in a Timber log message. ```java Timber.d("success = %b", taskName); ``` -------------------------------- ### Planting Timber Trees for Configuration Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/INDEX.md Configure Timber by planting different trees. Use Timber.DebugTree() for debugging and custom trees like CrashReportingTree() or RemoteLoggingTree() for releases. Conditional planting is also supported. ```kotlin // Debug configuration Timber.plant(Timber.DebugTree()) // Release configuration Timber.plant(CrashReportingTree()) Timber.plant(RemoteLoggingTree()) // Conditional configuration if (shouldEnableFileLogging) { Timber.plant(FileLoggingTree()) } ``` -------------------------------- ### Incorrect Argument Count Lint Example Source: https://github.com/jakewharton/timber/blob/trunk/README.md This example demonstrates a Lint error (TimberArgCount) where the number of arguments provided to a Timber logging call does not match the format string's requirements. ```java Timber.d("Hello %s %s!", firstName); ``` -------------------------------- ### treeCount Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/api-reference/timber.md Gets the number of currently planted trees. Thread-safe. ```APIDOC ## treeCount ### Description Gets the number of currently planted trees. Thread-safe. ### Method ```kotlin val treeCount: Int ``` ### Returns `Int` - The number of trees currently in the forest. ### Example ```kotlin println("Tree count: ${Timber.treeCount}") ``` ``` -------------------------------- ### Configure Timber in Application Startup Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/configuration.md This snippet shows the recommended location and pattern for configuring Timber within your Application class's onCreate() method. It conditionally plants DebugTree for debug builds and a CrashReportingTree for release builds. ```kotlin class MyApplication : Application() { override fun onCreate() { super.onCreate() configureTimbr() } private fun configureTimbr() { if (BuildConfig.DEBUG) { Timber.plant(Timber.DebugTree()) } else { Timber.plant(CrashReportingTree()) } } } ``` -------------------------------- ### Plant Multiple Logging Trees Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/api-reference/timber.md Use the varargs version of `plant()` to add multiple `Tree` instances to the forest simultaneously. All trees are validated before being added atomically. ```kotlin fun plant(vararg trees: Tree) ``` ```kotlin val debugTree = Timber.DebugTree() val crashTree = CrashReportingTree() Timber.plant(debugTree, crashTree) ``` -------------------------------- ### Format String Logging Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/README.md Demonstrates using Java's String.format() syntax with Timber for logging different data types. ```kotlin Timber.d("Hello %s", name) // String Timber.d("Count: %d", count) // Integer Timber.d("Progress: %.1f%%", 95.5) // Float with precision Timber.d("Enabled: %b", true) // Boolean Timber.d("Hex: %x", 255) // Hexadecimal ``` -------------------------------- ### Migrate Log.i to Timber.i Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/usage-guide.md Replace `Log.i` calls with `Timber.i` for simplified info logging. ```java Timber.i(msg) ``` -------------------------------- ### Override createStackElementTag Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/api-reference/debug-tree.md Override the createStackElementTag method to customize how log tags are generated. This example includes the line number in the tag. ```kotlin class CustomDebugTree : Timber.DebugTree() { override fun createStackElementTag(element: StackTraceElement): String? { // Include line number in tag val baseName = super.createStackElementTag(element) return "$baseName:${element.lineNumber}" } } ``` -------------------------------- ### Programmatic File-Based Logging Configuration Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/configuration.md Parse configuration files in your application and use the results to determine which Timber trees to plant. ```kotlin fun loadLoggingConfig(configFile: File): LoggingConfig { return Json.decodeFromString(configFile.readText()) } fun configureLogging(config: LoggingConfig) { Timber.uprootAll() if (config.debugLogging) { Timber.plant(Timber.DebugTree()) } if (config.crashReporting) { Timber.plant(CrashReportingTree()) } } ``` -------------------------------- ### Migrate Log.wtf to Timber.wtf Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/usage-guide.md Replace `Log.wtf` calls with `Timber.wtf` for simplified 'what a terrible failure' logging. ```java Timber.wtf(msg) ``` -------------------------------- ### Migrate Log.w to Timber.w Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/usage-guide.md Replace `Log.w` calls with `Timber.w` for simplified warning logging. ```java Timber.w(msg) ``` -------------------------------- ### Custom Filtering Tree Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/api-reference/tree.md Example of a custom Timber Tree that filters logs, only allowing messages with priority INFO or above to be passed to a wrapped tree. ```kotlin class FilteringTree(private val wrappedTree: Timber.Tree) : Timber.Tree() { override fun isLoggable(tag: String?, priority: Int): Boolean { return priority >= Log.INFO // Only info and above } override fun log(priority: Int, tag: String?, message: String, t: Throwable?) { wrappedTree.log(priority, tag, message, t) } } ``` -------------------------------- ### Publish Artifacts with Gradle Source: https://github.com/jakewharton/timber/blob/trunk/RELEASING.md Clean and publish artifacts using the Gradle wrapper. This is a manual step before promoting on Sonatype Nexus. ```bash ./gradlew clean publish ``` -------------------------------- ### Planting Logging Trees Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/README.md Add different types of trees to the Timber forest to handle log output. Each tree can implement custom logging behavior. ```kotlin Timber.plant(Timber.DebugTree()) // Custom tree: crash reporting Timber.plant(CrashReportingTree()) // Custom tree: remote logging Timber.plant(RemoteLoggingTree()) // All trees receive all log calls Timber.d("Message") // Goes to all three trees ``` -------------------------------- ### Migrate from android.util.Log to Timber Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/README.md Shows the equivalent Timber calls for common android.util.Log statements. Use Timber for simpler and more concise logging. ```kotlin import android.util.Log Log.d(TAG, "message") Log.d(TAG, String.format("Hello %s", name)) ``` ```kotlin import timber.log.Timber Timber.d("message") Timber.d("Hello %s", name) ``` -------------------------------- ### Log Capture for Testing Timber Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/usage-guide.md A Timber.Tree implementation that captures log messages for assertion in tests. Provides methods to get and clear captured logs. ```kotlin class LogCapture : Timber.Tree() { private val messages = mutableListOf() fun getLogs(): List = messages.toList() fun clear() = messages.clear() override fun log(priority: Int, tag: String?, message: String, t: Throwable?) { messages.add(LogMessage(priority, tag, message, t)) } data class LogMessage( val priority: Int, val tag: String?, val message: String, val exception: Throwable? ) } // In test val capture = LogCapture() Timber.plant(capture) testCode() val logs = capture.getLogs() assert(logs.any { it.message.contains("expected") }) ``` -------------------------------- ### Plant a Single Logging Tree Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/api-reference/timber.md Use `plant()` to add a new `Tree` instance to the Timber forest. This tree will receive all subsequent log messages. Ensure the tree is not null or the Timber forest itself. ```kotlin fun plant(tree: Tree) ``` ```kotlin val debugTree = Timber.DebugTree() Timber.plant(debugTree) Timber.d("Message routed to debug tree") ``` -------------------------------- ### Timber Tree Management Methods Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/INDEX.md Illustrates how to manage logging trees with Timber. Use these methods to add, remove, and query the active logging trees. ```kotlin // Tree management Timber.plant(tree) // Add tree Timber.plant(*trees) // Add multiple Timber.uproot(tree) // Remove tree Timber.uprootAll() // Remove all Timber.forest() // Get all trees Timber.treeCount // Tree count ``` -------------------------------- ### Migrate Log.v to Timber.v Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/usage-guide.md Replace `Log.v` calls with `Timber.v` for simplified verbose logging. ```java Timber.v(msg) ``` -------------------------------- ### Basic Timber Logging Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/INDEX.md Log simple messages, formatted strings, exceptions with context, and messages with custom tags. Ensure Timber is planted before use. ```kotlin Timber.d("Simple message") Timber.d("Formatted %s %d", name, age) Timber.d(exception, "Context about error") Timber.tag("Custom").d("Tagged message") ``` -------------------------------- ### Plant Logging Trees with Timber Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/usage-guide.md Add one or more logging trees to Timber. This is the first step to enable logging. You can plant a single DebugTree or multiple custom trees. ```kotlin // Single tree Timber.plant(Timber.DebugTree()) // Multiple trees at once Timber.plant( Timber.DebugTree(), CrashReportingTree(), AnalyticsTree() ) // Plant separately Timber.plant(debugTree) Timber.plant(crashTree) ``` -------------------------------- ### Migrate Log.d with String.format to Timber.d Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/usage-guide.md Replace `Log.d` calls using `String.format` with Timber's direct formatting. ```java Timber.d(...) ``` -------------------------------- ### Get Timber Forest as a Tree Instance Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/api-reference/timber.md Use the `asTree()` inline function to obtain the entire Timber forest typed as a `Tree`. This is useful for dependency injection or testing scenarios. ```kotlin inline fun asTree(): Tree ``` ```kotlin val logger: Timber.Tree = Timber.asTree() logger.d("Logging via injected instance") ``` -------------------------------- ### Multi-Level Filtering Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/configuration.md Configure multiple Timber trees with different filtering levels. This allows for granular control over what gets logged to different destinations (e.g., logcat, crash reporter, remote server). ```kotlin // Only DEBUG and above to logcat Timber.plant(Timber.DebugTree()) // Only WARN and above to crash reporter Timber.plant(FilteringTree(Log.WARN, CrashReportingTree())) // Only ERROR to remote server Timber.plant(FilteringTree(Log.ERROR, RemoteLoggingTree())) ``` -------------------------------- ### DebugTree Constructor Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/api-reference/debug-tree.md Creates a new DebugTree instance with default settings. This is the primary way to initialize DebugTree for use with Timber. ```APIDOC ## DebugTree() ### Description Creates a new `DebugTree` with default settings. No parameters required. ### Constructor `constructor()` ### Example ```kotlin Timber.plant(Timber.DebugTree()) ``` ``` -------------------------------- ### Implement Core Logging with log Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/api-reference/tree.md This abstract method must be implemented by subclasses to define the actual destination and format of log messages. It receives already filtered and formatted messages. ```kotlin protected abstract fun log(priority: Int, tag: String?, message: String, t: Throwable?) ``` ```kotlin class FileLoggingTree(private val outputFile: File) : Timber.Tree() { override fun log(priority: Int, tag: String?, message: String, t: Throwable?) { val timestamp = SimpleDateFormat("HH:mm:ss", Locale.US).format(Date()) val logLine = "[$timestamp] ${getPriorityName(priority)} $tag: $message\n" outputFile.appendText(logLine) } private fun getPriorityName(priority: Int) = when(priority) { Log.VERBOSE -> "V" Log.DEBUG -> "D" Log.INFO -> "I" Log.WARN -> "W" Log.ERROR -> "E" Log.ASSERT -> "A" else -> "?" } } ``` -------------------------------- ### Timber Logging Levels and Methods Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/INDEX.md Shows the available logging methods in Timber corresponding to different priority levels. Use these methods to log messages according to their severity. ```kotlin // Logging (18 method overloads) Timber.v(message?, *args) // Log verbose Timber.d(message?, *args) // Log debug Timber.i(message?, *args) // Log info Timber.w(message?, *args) // Log warning Timber.e(message?, *args) // Log error Timber.wtf(message?, *args) // Log assert/WTF Timber.log(priority, message?, *args) // Generic priority ``` -------------------------------- ### Programmatic Environment-Based Logging Configuration Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/configuration.md Implement environment-based logging configuration in your application code by checking sources like BuildConfig or SharedPreferences. ```kotlin fun shouldEnableVerboseLogging(): Boolean { // Check BuildConfig, SharedPreferences, or other sources return BuildConfig.DEBUG || BuildConfig.FLAVOR == "dev" } ``` -------------------------------- ### Test Fixture for Timber Logging Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/usage-guide.md Sets up Timber for testing by planting a TestLoggingTree before tests and removing it afterward. Ensures a clean logging state for each test. ```kotlin @RunWith(RobolectricTestRunner::class) class MyActivityTest { @Before fun setUp() { // Clear any previously planted trees Timber.uprootAll() // Plant a test tree that captures logs Timber.plant(TestLoggingTree()) } @After fun tearDown() { Timber.uprootAll() } @Test fun testLogging() { val activity = ActivityScenario.launch(MyActivity::class.java) activity.onActivity { activity -> activity.performAction() // Verify logs were produced } } private class TestLoggingTree : Timber.Tree() { val logs = mutableListOf() override fun log(priority: Int, tag: String?, message: String, t: Throwable?) { logs.add("[$tag] $message") } } } ``` -------------------------------- ### Exception Logging Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/README.md Shows how to log exceptions with Timber, including with and without a context message. ```kotlin // Exception only Timber.e(exception) // Exception with context message Timber.e(exception, "Operation failed") // Multiple levels can log exceptions Timber.d(exception, "Debug info: %s", detail) Timber.w(exception, "Warning: %s", reason) ``` -------------------------------- ### Migrate Log.e to Timber.e Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/usage-guide.md Replace `Log.e` calls with `Timber.e` for simplified error logging. ```java Timber.e(msg) ``` -------------------------------- ### Runtime Configuration Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/configuration.md Dynamically add or remove Timber trees at runtime based on certain conditions. This includes planting remote logging trees with error handling and removing debug trees. ```kotlin // Add logging tree dynamically at runtime if (someRuntimeCondition) { try { Timber.plant(RemoteLoggingTree(endpoint)) } catch (e: IllegalArgumentException) { Log.e("App", "Failed to plant remote tree", e) } } // Remove trees at runtime if (debugTreeInstance != null) { Timber.uproot(debugTreeInstance) } ``` -------------------------------- ### Dynamic Reconfiguration of Timber Trees Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/configuration.md Dynamically reconfigure Timber at runtime by removing all existing trees and planting new ones, or by selectively updating specific trees. ```kotlin // Remove all trees Timber.uprootAll() // Plant new trees Timber.plant(newTree1, newTree2) // Or selectively update val oldTree = debugTree Timber.uproot(oldTree) Timber.plant(newDebugTree) ``` -------------------------------- ### Feature-Based Configuration Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/configuration.md Configure Timber trees dynamically based on feature flags defined in BuildConfig. This allows enabling or disabling specific logging behaviors like crash reporting or analytics. ```kotlin Timber.plant(Timber.DebugTree()) if (BuildConfig.ENABLE_CRASH_REPORTING) { Timber.plant(CrashReportingTree()) } if (BuildConfig.ENABLE_ANALYTICS) { Timber.plant(AnalyticsTree()) } ``` -------------------------------- ### Test Log Formatting Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/errors.md This snippet demonstrates how to test Timber's log formatting to ensure it does not throw exceptions with valid arguments. It plants a DebugTree, performs a log call with formatted arguments, and then uproots all trees. ```kotlin import timber.log.Timber @Test fun testLogFormatting() { Timber.plant(Timber.DebugTree()) // Should not throw Timber.d("User %s age %d country %s", "John", 30, "US") Timber.uprootAll() } ``` -------------------------------- ### Triggering IllegalArgumentException: Planting Forest into Itself Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/errors.md Demonstrates how calling Timber.plant with Timber.asTree() will throw an IllegalArgumentException. ```kotlin // Throws IllegalArgumentException: "Cannot plant Timber into itself." Timber.plant(Timber.asTree()) ``` -------------------------------- ### Thread-Safe Timber Configuration Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/configuration.md Timber's configuration methods like `plant()` and `uproot()` are synchronized, making it safe to plant trees from any thread. ```kotlin // Safe to call from any thread Thread { Timber.plant(someTree) }.start() ``` -------------------------------- ### plant (single tree) Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/api-reference/timber.md Adds a new logging tree to the forest. All subsequent logging calls are routed to all planted trees. Thread-safe. ```APIDOC ## plant (single tree) ### Description Adds a new logging tree to the forest. All subsequent logging calls are routed to all planted trees. Thread-safe. ### Method ```kotlin fun plant(tree: Tree) ``` ### Parameters #### Path Parameters - **tree** (Tree) - Required - The tree instance to add. Cannot be null or the Timber forest itself. ### Throws `IllegalArgumentException` if tree is null or if tree is the Timber forest instance. ### Example ```kotlin val debugTree = Timber.DebugTree() Timber.plant(debugTree) Timber.d("Message routed to debug tree") ``` ``` -------------------------------- ### Timber Logging with Explicit Tags Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/api-reference/debug-tree.md Shows how to explicitly set a tag for Timber log messages and how subsequent messages will use auto-derived tags. ```kotlin Timber.tag("MyTag").d("Tagged message") Timber.d("Next message with auto-derived tag") ``` -------------------------------- ### Timber Tagging Method Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/INDEX.md Demonstrates how to set a one-time tag for log messages using Timber. This tag will be prepended to log output for that specific call. ```kotlin // Tagging Timber.tag(tag) // Set one-time tag ``` -------------------------------- ### Migrate Log.d with Exception to Timber.d Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/usage-guide.md Replace `Log.d` calls with an exception and message to `Timber.d` with the exception first. ```java Timber.d(e, msg) ``` -------------------------------- ### w (Warning) Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/api-reference/tree.md Logs a warning message (Log.WARN / 5). Supports logging a message, a message with arguments, an exception, or an exception with a message and arguments. ```APIDOC ## w (Warning) ### Description Logs a warning message (Log.WARN / 5). Supports logging a message, a message with arguments, an exception, or an exception with a message and arguments. ### Method ``` open fun w(message: String?, vararg args: Any?) open fun w(t: Throwable?, message: String?, vararg args: Any?) open fun w(t: Throwable?) ``` ``` -------------------------------- ### Dependency Injection for Timber Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/README.md Inject Timber as a Tree into classes for logging within dependency-injected environments. ```kotlin class MyActivity @Inject constructor() { private val logger: Timber.Tree = Timber.asTree() fun doSomething() { logger.d("Something done") } } ``` -------------------------------- ### Testing Timber Logs Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/README.md Create a custom Timber Tree to capture log messages during tests and assert their content. ```kotlin class LogCapture : Timber.Tree() { val messages = mutableListOf() override fun log(priority: Int, tag: String?, message: String, t: Throwable?) { messages.add("[$tag] $message") } } // In test val capture = LogCapture() Timber.plant(capture) testCode() assert(capture.messages.any { it.contains("expected") }) ``` -------------------------------- ### Routing Logs to Multiple Destinations Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/usage-guide.md Plants multiple Timber trees to send logs to different destinations simultaneously, such as logcat, a crash reporter, and a remote server. ```kotlin class MyApplication : Application() { override fun onCreate() { super.onCreate() // Debug output to logcat Timber.plant(Timber.DebugTree()) // Warnings and errors to crash reporter Timber.plant(FilteredTree(Log.WARN, CrashReportingTree())) // Errors only to remote server Timber.plant(FilteredTree(Log.ERROR, RemoteLoggingTree())) } } ``` -------------------------------- ### Conditional Trees Based on Build Type Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/configuration.md Plant different Timber trees based on whether the application is a debug or release build. Debug builds log verbosely to logcat, while release builds focus on crash reporting and analytics. ```kotlin class MyApplication : Application() { override fun onCreate() { super.onCreate() if (BuildConfig.DEBUG) { // Debug: verbose logging to logcat Timber.plant(Timber.DebugTree()) } else { // Release: crash reporting and analytics only Timber.plant(CrashReportingTree()) Timber.plant(AnalyticsTree()) } } } ``` -------------------------------- ### Correct Usage of Timber.plant() Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/configuration.md Use Timber.plant() without any constructor parameters for Timber and DebugTree. Custom Tree subclasses can accept parameters. ```kotlin // ✓ Correct: no parameters Timber.plant(Timber.DebugTree()) ``` ```kotlin // ✗ Wrong: DebugTree has no constructor parameters // Timber.plant(Timber.DebugTree(someOption)) // Compile error ``` -------------------------------- ### Logging to Multiple Destinations Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/README.md Plant multiple Timber trees to send logs to different destinations simultaneously, such as Logcat, files, or crash reporters. ```kotlin Timber.plant(Timber.DebugTree()) // Logcat Timber.plant(FilteringTree(Log.INFO, FileTree())) // File Timber.plant(FilteringTree(Log.ERROR, CrashTree())) // Crash reporter ``` -------------------------------- ### File-Based Logging Tree Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/configuration.md Implement a custom Timber Tree to log messages to a file. This involves appending formatted log lines to a specified file. ```kotlin class FileLoggingTree(private val logFile: File) : Timber.Tree() { override fun log(priority: Int, tag: String?, message: String, t: Throwable?) { val timestamp = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US).format(Date()) val line = "[$timestamp] $tag: $message\n" logFile.appendText(line) } } // Configure Timber.plant(FileLoggingTree(File(cacheDir, "logs.txt"))) ``` -------------------------------- ### Filtering Timber Logs with pidcat Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/api-reference/debug-tree.md Illustrates how to use a log reader like pidcat to filter Timber logs, specifically for messages originating from a particular Activity. ```bash # Filter Timber logs for a specific Activity pidcat.py MainActivity ``` -------------------------------- ### plant (varargs) Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/api-reference/timber.md Adds multiple logging trees to the forest in one call. All trees are validated before any are added. Thread-safe. ```APIDOC ## plant (varargs) ### Description Adds multiple logging trees to the forest in one call. All trees are validated before any are added. Thread-safe. ### Method ```kotlin fun plant(vararg trees: Tree) ``` ### Parameters #### Path Parameters - **trees** (Array) - Required - One or more tree instances to add. None can be null or the Timber forest itself. ### Throws `IllegalArgumentException` if any tree is null or if any tree is the Timber forest instance. ### Example ```kotlin val debugTree = Timber.DebugTree() val crashTree = CrashReportingTree() Timber.plant(debugTree, crashTree) ``` ``` -------------------------------- ### DebugTree API Reference Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/types.md The signature for Timber.DebugTree, showing its constructor and key methods for creating tags and logging. ```kotlin open class Timber.DebugTree : Timber.Tree { constructor() protected open fun createStackElementTag(element: StackTraceElement): String? override fun log(priority: Int, tag: String?, message: String, t: Throwable?) } ``` -------------------------------- ### i (Info) Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/api-reference/tree.md Logs an info message (Log.INFO / 4). Supports logging a message, a message with arguments, an exception, or an exception with a message and arguments. ```APIDOC ## i (Info) ### Description Logs an info message (Log.INFO / 4). Supports logging a message, a message with arguments, an exception, or an exception with a message and arguments. ### Method ``` open fun i(message: String?, vararg args: Any?) open fun i(t: Throwable?, message: String?, vararg args: Any?) open fun i(t: Throwable?) ``` ``` -------------------------------- ### Conditional Debug vs. Release Logging Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/usage-guide.md Plants a debug tree for development builds and a crash reporting tree for production builds. Ensure BuildConfig.DEBUG is correctly configured. ```kotlin class MyApplication : Application() { override fun onCreate() { super.onCreate() if (BuildConfig.DEBUG) { // Development: verbose logging to logcat Timber.plant(Timber.DebugTree()) } else { // Production: only errors to crash reporting Timber.plant(CrashReportingTree()) } } private class CrashReportingTree : Timber.Tree() { override fun isLoggable(tag: String?, priority: Int): Boolean { return priority >= Log.ERROR } override fun log(priority: Int, tag: String?, message: String, t: Throwable?) { CrashReporting.log(priority, tag, message, t) } } } ``` -------------------------------- ### wtf (Assert) Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/api-reference/tree.md Logs an assert-level message (Log.ASSERT / 7). Supports logging a message, a message with arguments, an exception, or an exception with a message and arguments. ```APIDOC ## wtf (Assert) ### Description Logs an assert-level message (Log.ASSERT / 7). Supports logging a message, a message with arguments, an exception, or an exception with a message and arguments. ### Method ``` open fun wtf(message: String?, vararg args: Any?) open fun wtf(t: Throwable?, message: String?, vararg args: Any?) open fun wtf(t: Throwable?) ``` ``` -------------------------------- ### forest Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/api-reference/timber.md Returns a copy of all currently planted trees. Modifications to the returned list do not affect the forest. Thread-safe. ```APIDOC ## forest ### Description Returns a copy of all currently planted trees. Modifications to the returned list do not affect the forest. Thread-safe. ### Method ```kotlin fun forest(): List ``` ### Returns `List` - An unmodifiable list of all planted trees. ### Example ```kotlin val allTrees = Timber.forest() println("Planted ${allTrees.size} trees") ``` ``` -------------------------------- ### Timber Static Methods Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/README.md These are the static methods available on the main Timber class for managing logging behavior and initiating log messages. ```APIDOC ## Timber Static Methods ### Description Static methods on the `Timber` class to control logging, such as planting and removing trees, setting tags, and initiating log messages at various levels. ### Methods - `v(message?, *args)`: Log verbose. - `d(message?, *args)`: Log debug. - `i(message?, *args)`: Log info. - `w(message?, *args)`: Log warning. - `e(message?, *args)`: Log error. - `wtf(message?, *args)`: Log assert. - `log(priority, message?, *args)`: Log at arbitrary level. - `tag(tag)`: Set one-time explicit tag. - `plant(tree)`: Add a tree to the forest. - `plant(vararg trees)`: Add multiple trees. - `uproot(tree)`: Remove a tree. - `uprootAll()`: Remove all trees. - `forest()`: Get all planted trees. - `asTree()`: Get forest as Tree instance. ### Properties - `treeCount` (Int): Number of planted trees. ``` -------------------------------- ### Early Filtering with isLoggable Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/usage-guide.md Implement the `isLoggable` method to filter out lower-priority logs (DEBUG, VERBOSE) early, reducing unnecessary processing. ```kotlin override fun isLoggable(tag: String?, priority: Int): Boolean { return priority >= Log.INFO // Skip DEBUG and VERBOSE } ``` -------------------------------- ### Using Format Strings for Logging Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/README.md Timber supports Java's String.format() syntax for cleaner log messages, avoiding manual string concatenation. ```kotlin // Old way: concatenation Log.d(TAG, "User " + name + " is " + age + " years old") // Timber way: format strings Timber.d("User %s is %d years old", name, age) ``` -------------------------------- ### Migrate Log.d to Timber.d Source: https://github.com/jakewharton/timber/blob/trunk/_autodocs/usage-guide.md Replace `Log.d` calls with `Timber.d` for simplified debug logging. ```java Timber.d(msg) ```