ведение журнала kotlin с лямбда-параметрами

В log4j2 у нас есть удобная функция, которая описывается как

// Java-8 style optimization: no need to explicitly check the log level:
// the lambda expression is not evaluated if the TRACE level is not enabled
logger.trace("Some long-running operation returned {}", () -> expensiveOperation());

моя попытка использовать это в Котлин

log.debug("random {}", { UUID.randomUUID() })

которая будет печатать

random Function0<java.util.UUID>

как мы используем лямбда-логирование аргументов с помощью kotlin? Или как мы явно скажем Котлину, какой метод вызывать?

3 ответов


проблема в том, что debug() перегружен и имеет другой метод, принимающий объект vararg в качестве аргумента. Котлин выбирает эту перегрузку, а не ту, которая принимает Supplier<?> как аргумент, потому что он не знает, что лямбда-выражение должно быть поставщиком.

просто укажите его в качестве поставщика:

log.debug("random {}", Supplier { UUID.randomUUID() })

я написал класс, который делает это весело, чтобы использовать... Чтобы мы могли писать такие вещи, как

log.debug { "some $thing is $that" }

что эквивалентно ленивому журналированию лямбда, как

log.debug("some {} is {}", ()->thing, ()->that)

вы даже не нужны эти {} для параметризации строки, и у вас есть все исходные методы регистратора, поскольку это делегат...

вот класс для тех, кто хотел бы его использовать...

import org.apache.logging.log4j.util.Supplier

class Logger(private val logger: org.apache.logging.log4j.Logger) : org.apache.logging.log4j.Logger by logger {

    fun info(supplier: () -> String) {
        logger.info(Supplier { supplier.invoke() })
    }

    fun debug(supplier: () -> String) {
        logger.debug(Supplier { supplier.invoke() })
    }

    fun warn(supplier: () -> String) {
        logger.warn(Supplier { supplier.invoke() })
    }

    fun error(supplier: () -> String) {
        logger.error(Supplier { supplier.invoke() })
    }

    fun trace(supplier: () -> String) {
        logger.trace(Supplier { supplier.invoke() })
    }
}

или если вы хотите воспользоваться удивительными ссылками на источник в логах вы можете сделать

import org.apache.logging.log4j.util.Supplier

class Logger(val logger: org.apache.logging.log4j.Logger) : org.apache.logging.log4j.Logger by logger {

    inline fun info(crossinline supplier: () -> String) {
        logger.info(Supplier { supplier.invoke() })
    }

    inline fun debug(crossinline supplier: () -> String) {
        logger.debug(Supplier { supplier.invoke() })
    }

    inline fun warn(crossinline supplier: () -> String) {
        logger.warn(Supplier { supplier.invoke() })
    }

    inline fun error(crossinline supplier: () -> String) {
        logger.error(Supplier { supplier.invoke() })
    }

    inline fun trace(crossinline supplier: () -> String) {
        logger.trace(Supplier { supplier.invoke() })
    }
}

проверить https://github.com/MicroUtils/kotlin-logging . Он также предоставляет эти функции:

удобная и исполнительная библиотека журналов, обертывающая slf4j с расширениями Kotlin.

методы журнала вызовов, не проверяя, включен ли соответствующий уровень журнала:

logger.debug { "Some $expensive message!" }

за кулисами дорогое сообщение не оценивается, если отладка не включена:

if (logger.isDebugEnabled) logger.debug("Some $expensive message!")

определите регистратор, без явного указание имени класса:

// Place definition above class declaration to make field static  
private val logger = KotlinLogging.logger {}