개요

  • Android 개발시 logging 에는 Logcat 을 기본으로 사용한다.

  • println 으로도 logging 을 할 수 있지만, 단순 logcat 창에 출력 되는 기능만 가능하다.

  • logger 라는 library 도 있지만, 2018.03 월 release 이후, update가 되지 않고 있다.

  • timber 라는 libarary 를 사용하면, 커스텀도 가능하고, Logcat에 작성해야 하는 “TAG” 도 굳이 작성하지 않아도 자동으로 어느 파일에서 log가 남는지 알 수 있다.

    • OkHttpHttpLoggingInterceptor 에도 timber를 적용과 Custom이 가능하다.
    • 그 외에 logging 하는 방법은 기존 Logcat 과 동일하다. Log.d( , ) -> Timber.d()

3b59be5a-04be-47ed-b9ba-178da5c62a06.png 58f200a8-d717-44c4-a0b3-6c2f5a4e97a0.png

세팅

  • gradle KTS 을 사용한다고 가정
  • Version Catalog 를 사용한다고 가정

libs.versions.toml

1
2
3
4
5
[versions]
timber = "5.0.1" #23.12.10 기준 최신 버전

[libraries]
timber = { module = "com.jakewharton.timber:timber", version.ref = "timber" }

app 모듈의 build.gradle.kts

1
2
3
4
dependencies {
    //...
    implementation(libs.timber)
}

Application()을 상속 받는 .kt 파일에 timber library을 initialize 한다.

1
2
3
4
5
6
7
8
class MainApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        if (BuildConfig.DEBUG) {
            Timber.plant(Timber.DebugTree())
        }
    }
}

AndroidManifest 파일

    <application
        android:name=".MainApplication"
        android:icon="@mipmap/ic_launcher"
        //...

Custom logging with timber

  • createStackElementTag 함수를 override 해서, logging 되는 line, method, class를 logcat에 자동으로 표시할 수 있게 된다.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class MainApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        if (BuildConfig.DEBUG) {
            Timber.plant(object : Timber.DebugTree() {
                override fun createStackElementTag(element: StackTraceElement): String? {
                    return String.format(
                        "Class:%s: Line: %s, Method: %s",
                        super.createStackElementTag(element),
                        element.lineNumber,
                        element.methodName
                    )
                }
            })
        } else {
            Timber.plant(ReleaseTree())
        }
    }
}

ReleaseTree 를 따로 생성하여, release 모드 일때, error report 를 보낼 수 있게 할 수 있다.

1
2
3
4
5
6
7
class ReleaseTree : @NotNull Timber.Tree() {
    override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
        if (priority == Log.ERROR || priority == Log.WARN) {
            //SEND ERROR REPORTS TO YOUR Crashlytics.
        }
    }
}

장점

  • No need to write TAGs

    • Timber가 자동으로 TAGs 를 생성한다.
  • Customized behavior

    • Custom Timber 트리를 사용하여 Logcat에 로깅하는 대신, Crashlytics service로 log를 전송할 수 있다.
  • Customized Meta-Data

    • createStackElementTag 함수를 통해 line, method, class를 logcat에 자동으로 표시할 수 있게 된다.
  • Lightweight

  • 주기적으로 업데이트 되는 open-source

    • 2021.08.13 에 5.0.1 버전이 release 되었다.
    • 다른 logging 라이브러리(ex.logger)에 비해 비교적 최근 까지 업데이트 된다.

참고 사항

  • HttpLoggingInterceptor 사용시, log 함수를 override 하여, debug 모드 일때만, logging 하게 할 수 있다.
    • Custom 하여, Json을 pretty 하게 출력할 수 도 있다.
1
2
3
4
5
6
7
@Singleton
@Provides
fun provideLoggingInterceptor(): HttpLoggingInterceptor { // Hilt로 DI를 하는 경우
    val logger = HttpLoggingInterceptor.Logger { message -> Timber.tag("okHttp").d(message) }
    return HttpLoggingInterceptor(logger)
        .setLevel(HttpLoggingInterceptor.Level.BODY)
}
  • Timber.d("") 처럼 ""(empty string) 을 logging 하려면, Custom을 해야 한다.
1
2
3
4
5
6
7
override fun d(message: String?, vararg args: Any?) {
    if (message?.length == 0) {
        super.d("EMPTY_STRING", *args)
    } else {
        super.d(message, *args)
    }
}

Reference