This article will explain a simple way in which you can obtain an instance of java.util.logging.Logger through dependency retrieval.

For dependency retrieval I am going to use the library Kodein. If you need an introduction to Kodein, please see this article in this blog.

The purpose of this article is to show you how to create a separate instance of Logger for every class, as well as how to automatically disable debug messages in production builds.

Without Kodein

To create a good enough effect without using Kodein, or dependency retrieval, just use the following line:

val Any.log get() = Logger.getLogger(this::class.java.name)!!

Because of the above global extension function, each time you use the expression log in your code, it will be interpreted as creation of an instance of java.util.logging.Logger with passing the name of the current class to its constructor.

The following sections will explain how to create a similar effect with dependency retrieval, so that a custom instance of Logger can be retrieved depending on the way you run your application.

You can see a separate article in this blog to find out how to configure Kodein specifically so that other kinds of instances are retrieved when the application is run with Android Espresso.

Configuring Kodein

To create a binding for Kodein, please use the following code:

bind<Logger>() with multiton { tag: String ->
    Logger.getLogger(tag)!!.apply {
        if (!BuildConfig.DEBUG) {
            setFilter { false }
        }
    }
}

This creates a multiton. According to Kodein documentation:

A multiton can be thought of a “singleton factory”: it guarantees to always return the same object given the same argument. In other words, for a given argument, the first time a multiton is called with this argument, it will call the function to create an instance; and will always yield that same instance when called with the same argument.

This line assures that a separate instance of Logger is created for every class, and that if it is not inside a debug build, it immediately calls the code setFilter { false } on it, which prevents any logging at all.

Because it is a multiton, as opposed to a factory that creates a new instance each time an instance is needed, the code setting the filter is invoked only once per every class that uses logging.

Retrieval

This is a generic function that retrieves multiton instnances using Kodein:

inline fun <reified A, reified T : Any> instance(arg: A): T {
    val result by Kodein.global.instance<A, T>(arg = arg)
    return result
}

This is how this function is called to retrieve an instance of the Logger:

val Any.log get() = instance<String, Logger>(this::class.java.name)

Because it is an extension function that extends Any, it can be called from all Kotlin classes, and each time it will return exactly one instance per class it was called from.

It is called like this:

class MainActivity: AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        log.info("line 1")
        log.info("line 2")
        log.info("line 3")
    }
}

Because it is a multiton, only one instance of Logger is created in the above code. Furthermode, because of the way Kodein is configured, if this is called from a production build, no debug messages will be produced.

You can see logging and dependency retrieval being used this way in my project Victor-Events.

Donations

If you’ve enjoyed this article, consider donating some bitcoin: bc1qncxh5xs6erq6w4qz3a7xl7f50agrgn3w58dsfp (you can also look at donations page).