1

I'm looking to replace

private static final Logger log = Logger.getLogger(MyClass.class);

with something that is a little less verbose and more idiomatic then

class MyClass {
    companion object {
        val log = LoggerFactory.getLogger(MyClass::class.java)
    }

    fun usage() {
        log.debug("Success")
    }
}

Bonus points for not having to delcare it in every class.

I tried:

interface HasLogger {
    val log: Logger
        get() = LoggerFactory.getLogger(this.javaClass)
}

But this results in a getLogger() call for every usage (inacceptable) also returns a logger for a subtype (not the one where it was declared).

oshai
  • 14,865
  • 26
  • 84
  • 140
atok
  • 5,880
  • 3
  • 33
  • 62

2 Answers2

1

You can create an utility method like

inline fun <reified T:Any> loggerFor() = LoggerFactory.getLogger(T::class.java)

And simply use it like

class MyClass {
    companion object {
        val log = loggerFor<MyClass>()
    }

    fun usage() {
        log.debug("Success")
    }
}

Alternatively you could use a file level private logger which saves you some typing, which only seems to be a good solution when you don't have multiple classes with their own loggers defined per file:

private val log = loggerFor<MyClass>()

class MyClass {
    fun usage() {
        log.debug("Success")
    }
}
M Platvoet
  • 1,679
  • 1
  • 10
  • 14
  • This is still a little much for my taste. But looks like it can work without using LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()) – atok Jun 08 '16 at 09:33
1

First, you can add extension functions for logger creation.

inline fun <reified T : Any> getLogger() = LoggerFactory.getLogger(T::class.java)
fun <T : Any> T.getLogger() = LoggerFactory.getLogger(javaClass)

Then you will be able to create a logger using the following code.

private val logger1 = getLogger<SomeClass>()
private val logger2 = getLogger()

Second, you can define an interface that provides a logger and its mixin implementation.

interface LoggerAware {
  val logger: Logger
}

class LoggerAwareMixin(containerClass: Class<*>) : LoggerAware {
  override val logger: Logger = LoggerFactory.getLogger(containerClass)
}

inline fun <reified T : Any> loggerAware() = LoggerAwareMixin(T::class.java)

This interface can be used in the following way.

class SomeClass : LoggerAware by loggerAware<SomeClass>() {
  // Now you can use a logger here.
}
Michael
  • 53,859
  • 22
  • 133
  • 139
  • 1
    Woah! That's cool! You can even replace reified T with MethodHandles.lookup().lookupClass() and get the same result withouth spelling out "SomeClass" for the second time: inline fun loggerAware() = HasLoggerMixin(MethodHandles.lookup().lookupClass()) – atok Jun 08 '16 at 09:45
  • @atok Yep, seems you can. – Michael Jun 08 '16 at 09:58
  • Thank you. I think you should post this in this question: http://stackoverflow.com/questions/34416869/idiomatic-way-of-logging-in-kotlin because its better then their results – atok Jun 08 '16 at 10:00