Thuy's Blog

Quickly get tags for logging in Kotlin

May 26, 2018

I was working on a project where legacy code heavily relied on Log API from Android SDK. Basically, the Log API requires you to specify a tag in order to write any log. So if you write a Java class, normally you will have to define a TAG constant like below.

public class PokemonStore {
  private final static String TAG = PokemonStore.class.getSimpleName();

  public void dispatch(final PokemonState.Action action) {
    Log.d(TAG, "dispatch -> " + action);
    // ...
  }

If you use Android Studio to automatically convert the above Java code into Kotlin, the corresponding Kotlin class actually looks more verbose with the companion object block:

class PokemonStore {
  fun dispatch(action: PokemonState.Action) {
    Log.d(TAG, "dispatch -> $action")
    // ...
  }

  companion object {
    private val TAG = PokemonStore::class.java.simpleName
  }
}

That may become a hassle if there’re a lot of Kotlin classes in your project. Alternatively, getting a tag becomes much easier with extension properties. So by defining an extension TAG property like this in a separate file:

// e.g. In TAG.kt file.
inline val <reified T> T.TAG: String
  get() = T::class.java.simpleName

Then you can access that TAG property in any Kotlin classes without having to define anything else:

class PokemonStore {
  fun dispatch(action: PokemonState.Action) {
    Log.d(TAG, "dispatch -> $action")
    // ...
  }
}

But there’s a small caveat. Sometimes you may be confused where the TAG property actually belongs to, especially when it comes to using function blocks with this as receivers, for example, apply. Consider the following sample test:

class HttpUrlTest {
  @Test
  fun `should construct HttpUrl correctly`() {
    println("$TAG: Running...")

    HttpUrl.Builder().apply {
      scheme("https")
      host("www.google.com")
      addPathSegment("search")
      addQueryParameter("q", "polar bears")
      println("$TAG: Finished build()")

      build()
    }.toString().shouldEqualTo("https://www.google.com/search?q=polar%20bears")
  }
}

You may think both TAGs above will have the same value which is HttpUrlTest but when you run the test, the result is different:

HttpUrlTest: Running...
Builder: Finished build()

This is simply because the second TAG is associated with the this receiver of the apply block. And that this is the Builder object which is retrieved via Builder().apply { ... }.


Thuy Trinh

Written by Thuy Trinh who lives and works in Frankfurt, Germany building robust Android apps. You should follow him on Twitter