Logging hiệu quả hơn với Timber

1. Introduction

Timber là một lớp tiện ích được xây dựng dựa trên Log class trong Android. Trong quá trình phát triển ứng dụng, chúng ta thường sử dụng log khá nhiều. Trước khi release, ta thường phải dọn sạch đống log đó bằng cách xóa chúng 1 cách thủ công hoặc nâng cao hơn chút thì check xem có đang ở môi trường debug không, khi đó mới đặt log. Một vấn đề khác là với mỗi loại log khác nhau thì bạn lại phải tạo phương thức riêng cho từng kiểu, điều đó khá là mất thời gian.

Trong bài viết nay mình sẽ cùng tìm hiểu Timber và những lợi ích mà nó mang lại 😄

2. Timber

Bên dưới là một vài câu lệnh debug sử dụng lớp Log mặc định :

int a = 100;
Log.e("TAG", String.format("Integer a value is: %d", a));
 
String name = "Android Studio";
Log.e("TAG", String.format("My name is: %s", name));

Ta nhận được output tương tự bằng cách sử dụng Timber như sau :

int a = 100;
Timber.e("Integer a value is: %d", a);
 
String name = "Android Studio";
Timber.e("My name is: %s", name);

Nếu để ý, bạn sẽ thấy 2 điểm khác biệt sau :

  • Timber không hề chứa thành phần TAG bởi nó sẽ tự động detect class nào đang gọi nó và thêm tên class thành TAG luôn.
  • Timber tự động định dạng String format.

3. Integrating Timber

OK, giờ hãy cùng tích hợp Timber vào project nhé.

  1. Mở build.gradle và thêm Timber dependency :

    // timber
    implementation 'com.jakewharton.timber:timber:4.7.1'
    
  2. Timber phải được khởi tạo ngay khi ứng dụng khởi động. Bởi vậy, Application class sẽ là nơi tốt nhất để thực hiện việc này. Tạo một class với tên App.java extend Application.

    • Khởi tạo Timber trong onCreate .
    • Ở đây, Timber.DebugTree() sẽ print log ở chế độ debug.
    • Nếu bạn muốn bắt exceptions ở chế độ release, bạn có thể tạo một Tree khác và xử lý nó.
    public class App extends Application {
        @Override
        public void onCreate() {
            super.onCreate();
    
            if (BuildConfig.DEBUG) {
                Timber.plant(new Timber.DebugTree());
            } else {
                Timber.plant(new ReleaseTree());
            }
        }
    }
    
  3. Như đã nói ở trên, bạn có thể tạo một custom Tree bằng cách exend class Timber.Tree. Bên dưới là một ví dụ về ReleaseTree :

    public class ReleaseTree extends Timber.Tree {
        @Override
        protected void log(int priority, String tag, String message, Throwable t) {
            if (priority == Log.VERBOSE || priority == Log.DEBUG) {
                return;
            }
    
            // log your crash to your favourite
            // Sending crash report to Firebase CrashAnalytics
    
            // FirebaseCrash.report(message);
            // FirebaseCrash.report(new Exception(message));
        }
    }
    
  4. Cuối cùng, thêm App vào thẻ <application> trong AndroidManifest.xml :

        <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="info.androidhive.timber">
    
        <application
            android:name=".App"
            ...>
    
        </application>
    
    </manifest>
    
  5. Timber đã sẵn sàng để sử dụng. Dưới đây là một số ví dụ cho các scenario khác nhau bạn có thể đọc thêm :

        public class MainActivity extends AppCompatActivity {
    
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
    
                ...
    
                // boolean
                boolean isWeekend = false;
                Timber.d("This prints the boolean value. Is weekend: %b", isWeekend);
    
                // integer
                int a = 100;
                Timber.d("Integer a value is: %d", a);
    
                // float
                float pi = 3.14159f;
                Timber.d("Pi value is: %f", pi);
            }
    
            @OnClick(R.id.btn_log_string)
            void logMessage() {
                Timber.d("Hello from Timber!");
    
                showToast();
            }
    
            @OnClick(R.id.btn_log_exception)
            void logException() {
                try {
                    int a = 10 / 0;
                    Timber.d("Value of a: %d", a);
                } catch (Exception e) {
                    Timber.e(e);
    
                    // or //
    
                    Timber.e("Exception in math operation: %s", e.getMessage());
                }
    
                showToast();
            }
    
            private void showToast() {
                Toast.makeText(getApplicationContext(), "Check LogCat for message or error!", Toast.LENGTH_SHORT).show();
            }
    }
    

3. Reference