https://kotlinlang.org logo
#android
Title
# android
s

Simon Schubert

08/12/2019, 4:14 PM
Usually one of the first things I create in a new android project is a L class. Which makes logging easier and also prevents logs to go into a non-debug versions
Copy code
object L {

    private const val TAG = "FOOBAR"

    fun e(log: String) {
        if (BuildConfig.DEBUG) {
            Log.e(TAG, log)
        }
    }
    ...
}
h

henrikhorbovyi

08/12/2019, 4:15 PM
Ah... cool! I use to do it too
t

Thomas

08/12/2019, 4:25 PM
I would use something like this instead. This way the log message is removed completely from the code in a release build.
Copy code
object L {

    const val TAG = "FOOBAR"

    inline fun e(log: () -> String) {
        if (BuildConfig.DEBUG) {
            Log.e(TAG, log())
        }
    }
    ...
}

L.e { "message to log" }
👍 1
s

Simon Schubert

08/12/2019, 4:35 PM
I would think that proguard/R8 will remove it if activated. But I didn't dig into it, yet. If proguard doesn't remove it I'm very happy to use your approach in my existing and future projects 🙂
h

henrikhorbovyi

08/12/2019, 4:41 PM
image.png
image.png
t

Thomas

08/12/2019, 4:41 PM
If you concat strings (or string templates) for the log message it will be converted to a StringBuilder in the bytecode. Proguard/R8 won’t remove those StringBuilders, even if they aren’t used. My example places the log message within the
if
statement. The compiled code will look like this:
Copy code
if (false) {
    Log.e(TAG, "message to log")
}
That way all the code is removed.
h

henrikhorbovyi

08/12/2019, 4:41 PM
ProGuard remove it
t

Thomas

08/12/2019, 4:42 PM
ProGuard remove it
Maybe it removes the logs but it does NOT remove the string concatenation that is needed for the message. So if someone decompiles your APK the log messages are still there
h

henrikhorbovyi

08/12/2019, 4:58 PM
Got it
s

Simon Schubert

08/12/2019, 5:23 PM
@Thomas Thanks for the explanation, now it's clear. I'm going to use that version from now on.
a

andym

08/12/2019, 9:55 PM
We’ve used Square’s Timber library to log everything in debug builds to Logcat, but for release, only log Warning or above, and only to a rolling log file in the user’s private storage (not to Logcat). We give users an option to report a problem thru the app by email. We include some relevant info about the device and app config settings, and the log file (zipped). We find we always need to tweak what we include in the logs, but still, paired with any context from the user’s email, they have been invaluable.
h

henrikhorbovyi

08/12/2019, 10:25 PM
Really cool @andym
f

florent

08/13/2019, 10:26 AM
Note that if you use that, you cannot use $it or ${myvar} as it is probable that it slow down the application a lot
t

Thomas

08/13/2019, 10:43 AM
@florent do you mean my example? The idea is to remove the logging completely. It can not slow down the application if all of the code is removed.
f

florent

08/13/2019, 11:13 AM
But L.e { "message to log" } will stay so the string will be generated even if it isn't displayed. So unless I am missing something, the system will still be slow down when complex string are created using for example $it to print a complex data class.
t

Thomas

08/13/2019, 11:17 AM
@florent no, that's incorrect. The lambda will be inlined within the
if (false) { ... }
statement so it will be removed completely when compiling a release build. That's the point of using this method instead of the original one that was posted.
f

florent

08/13/2019, 11:22 AM
But you stated that the concatenation will stay, that's where the performance will get reduced
t

Thomas

08/13/2019, 11:26 AM
@florent that was for the original post. The method I shared removes it completely. You can try it out for yourself by decompiling the APK and see the difference.