Что такое идиоматический способ Kotlin приобрести Logger?

Я ищу замену

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

с чем-то, что немного менее многословно и более идиоматично, чем

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

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

Бонусные баллы за то, что не нужно делать это в каждом классе.

Я попытался:

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

Но это приводит к вызову getLogger() для каждого использования (недопустимо), а также возвращает регистратор для подтипа (не того, где он был объявлен).


person atok    schedule 08.06.2016    source источник
comment
см. эту библиотеку: github.com/MicroUtils/kotlin.logging   -  person oshai    schedule 14.07.2016


Ответы (2)


Вы можете создать служебный метод, например

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

И просто используйте его как

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

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

В качестве альтернативы вы можете использовать частный регистратор на уровне файла, который сэкономит вам часть ввода, что кажется хорошим решением, только если у вас нет нескольких классов с их собственными регистраторами, определенными для каждого файла:

private val log = loggerFor<MyClass>()

class MyClass {
    fun usage() {
        log.debug("Success")
    }
}
person M Platvoet    schedule 08.06.2016
comment
Это все еще мало на мой вкус. Но похоже, что он может работать без ‹MyClass› с помощью LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()) - person atok; 08.06.2016

Во-первых, вы можете добавить функции расширения для создания регистратора.

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

Затем вы сможете создать регистратор, используя следующий код.

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

Во-вторых, вы можете определить интерфейс, который предоставляет регистратор и его реализацию миксина.

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)

Этот интерфейс можно использовать следующим образом.

class SomeClass : LoggerAware by loggerAware<SomeClass>() {
  // Now you can use a logger here.
}
person Michael    schedule 08.06.2016
comment
Вау! Это классно! Вы даже можете заменить reified T на MethodHandles.lookup().lookupClass() и получить тот же результат, не указывая SomeClass во второй раз: inline fun loggerAware() = HasLoggerMixin(MethodHandles.lookup().lookupClass()) - person atok; 08.06.2016
comment
@atok Да, кажется, можешь. - person Michael; 08.06.2016
comment
Спасибо. Я думаю, вы должны опубликовать это в этом вопросе: stackoverflow.com/questions/34416869/ потому что это лучше, чем их результаты - person atok; 08.06.2016