Timber là thư viện logging do Jake Wharton phát triển, bao bọc (wrapper) xung quanh android.util.Log. Timber khắc phục nhược điểm của Log chuẩn: tag tự động (tên class), không log trong release build, hỗ trợ tree tùy chỉnh (file, crashlytics, remote...), API ngắn gọn.
Tích hợp Timber
Bước 1: Thêm dependency
dependencies {
implementation 'com.jakewharton.timber:timber:5.0.1'
}
Bước 2: Khởi tạo trong Application class (Khuyến nghị)
import android.app.Application;
import timber.log.Timber;
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
if (BuildConfig.DEBUG) {
// Debug tree: log ra logcat với tag = class name
Timber.plant(new Timber.DebugTree());
} else {
// Release tree: gửi log đến Crashlytics, server, file...
Timber.plant(new ReleaseTree());
}
}
// Custom tree cho release
private static class ReleaseTree extends Timber.Tree {
@Override
protected void log(int priority, String tag, String message, Throwable t) {
if (priority == Log.VERBOSE || priority == Log.DEBUG || priority == Log.INFO) {
return; // Chỉ log Warning, Error trong release
}
// Gửi đến Firebase Crashlytics, Sentry, file log, server...
// FirebaseCrashlytics.getInstance().recordException(t);
}
}
}
AndroidManifest.xml
<application
android:name=".MyApplication"
... >
...
</application>
Sử dụng Timber
import timber.log.Timber;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Các level log
Timber.v("Verbose: Chi tiết debug"); // Verbose
Timber.d("Debug: Thông tin debug"); // Debug
Timber.i("Info: Thông tin chung"); // Info
Timber.w("Warning: Cảnh báo"); // Warning
Timber.e("Error: Lỗi"); // Error
Timber.wtf("What a Terrible Failure"); // WTF
// Format string (như String.format)
Timber.d("User %s đăng nhập lúc %d", "Nguyễn Văn A", System.currentTimeMillis());
// Log exception
try {
// code gây exception
} catch (Exception e) {
Timber.e(e, "Lỗi khi xử lý: %s", "đọc file");
}
// Tag tùy chỉnh (hiếm khi cần)
Timber.tag("Network").d("Request: %s", url);
}
}
So sánh Log vs Timber
| Đặc điểm | android.util.Log | Timber |
|---|---|---|
| Tag tự động | Không (phải hardcode) | Có (tên class) |
| Release build | Vẫn log (phải check BuildConfig.DEBUG) | Tự động tắt (DebugTree chỉ debug) |
| Exception logging | Log.e(tag, msg, e) | Timber.e(e, msg) |
| Extensibility | Khó | Dễ (Tree pattern) |
| String formatting | Manual | Built-in (varargs) |
| Kotlin support | Cơ bản | Tốt (extension functions) |
Advanced: Custom Tree
Log ra file (Internal storage)
public class FileLoggingTree extends Timber.Tree {
private final File logFile;
private static final int MAX_SIZE = 1024 * 1024; // 1MB
public FileLoggingTree(Context context) {
logFile = new File(context.getFilesDir(), "app.log");
}
@Override
protected void log(int priority, String tag, String message, Throwable t) {
if (priority < Log.INFO) return;
String logLine = String.format("[%s] %s: %s%n",
getTimestamp(), tag, message);
if (t != null) {
logLine += Log.getStackTraceString(t) + "\n";
}
try (FileWriter fw = new FileWriter(logFile, true)) {
fw.write(logLine);
// Rotate log nếu quá lớn
if (logFile.length() > MAX_SIZE) rotateLog();
} catch (IOException ignored) {}
}
private void rotateLog() { /* rename file cũ, tạo mới */ }
private String getTimestamp() {
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.US).format(new Date());
}
}
// Plant thêm: Timber.plant(new FileLoggingTree(this));
Logcat format đẹp hơn
// Tùy chỉnh DebugTree
Timber.plant(new Timber.DebugTree() {
@Override
protected String createStackElementTag(StackTraceElement element) {
// Tag format: ClassName.methodName:lineNumber
return String.format("%s.%s:%d",
element.getClassName().substring(element.getClassName().lastIndexOf('.') + 1),
element.getMethodName(),
element.getLineNumber());
}
});
Kotlin Extensions (Nếu dùng Kotlin)
// build.gradle.kts
implementation("com.jakewharton.timber:timber:5.0.1")
// Sử dụng
Timber.d { "Message lazy: ${expensiveComputation()}" } // Chỉ evaluate nếu log level đủ
Timber.tag("Network").d { "Response: $response" }
Chạy ứng dụng
Build debug → Logcat hiển thị log với tag tự động là tên class. Build release → Không log Verbose/Debug/Info, chỉ Warning/Error (nếu plant ReleaseTree).
Lưu ý
- Chỉ plant Timber **một lần** trong Application.onCreate()
- Không plant DebugTree trong release build
- Dùng
Timber.e(e, msg)cho exception - tự động log stacktrace - Tránh log thông tin nhạy cảm (token, password, PII) - ngay cả debug
- Proguard/R8 tự động loại bỏ Timber call nếu config đúng