Convenient Simplification of Kotlin LoggerFactory

What is the most convenient way to use SLF4J or other registration approaches with kotlin?

Usually a developer is busy with a template, for example

private val logger: Logger = LoggerFactory.getLogger(this::class.java) 

in each class to get the right registrar?

What are the most convenient ways to unify / simplify this with Kotlin?

+7
android logging kotlin slf4j
source share
5 answers

Here is a simple example that returns a lazily-initialized registrar from a related called link or standard property. I prefer to call from the called link because :: stands for reflection (logging related).

The class that Lazy<Logger> provides:

 class LoggingProvider<T : Any>(val clazz: KClass<T>) { operator fun provideDelegate(inst: Any?, property: KProperty<*>) = lazy { LoggerFactory.getLogger(clazz.java) } } 

Built-in functions for calling them:

 inline fun <reified T : Any> KCallable<T>.logger() = LoggingProvider(T::class) inline fun <reified T : Any> T.logger() = LoggingProvider(T::class) 

Here is an example of their use. The require statement in the initializer shows that the registrars have a link:

 class Foo { val self: Foo = this val logger by this.logger() val callableLogger by this::self.logger() init { require(logger === callableLogger) } } 
+1
source share

You can define an extension property for each type:

 val <T : Any> T.logger: Logger get() = LoggerFactory.getLogger(this::class.java) 

use it as follows:

 class X { init { logger.debug("init") } } 
+2
source share

I define this function in my projects to simplify the definition of the log. It takes advantage of the Kotlin reified types.

 // Defined in Utilities.kt inline fun <reified T:Any> logFor() = LoggerFactory.getLogger(T::class.java) 

Using:

 class MyClass { private val log = logFor<MyClass>() ... } 

Or, if you create a lot of them:

 class MyClass { companion object { private val log = logFor<MyClass>() } ... } 
+1
source share

if you don't like the template, you can always wrap log.info your own log helper:

 mylog.info(this, "data that needs to be logged") 

Then, in the background, there is some kind of hash file that keeps track of the classes of the this parameter, which can create a registrar instance for this class.

Other options may use AspectJ Weaving to insert a registrar into each class, but this, in my opinion, is too large.

0
source share

I defined a utility method for this

 fun getLogger(cl: KClass<*>): Logger { return LoggerFactory.getLogger(cl.java)!! } 

and now in each class I can use a registrar like this

 companion object { private val logger = getLogger(MyClass::class) } 
-2
source share

All Articles