Search code examples
kotlinloggingkotlin-extension

Extending Kotlin's extension


I'm trying to create an extension for KLogger/Logger which is an extension for slf4j's logger in order to better handle structured log messages. Could someone explain what's wrong with my code and how to fix it or work around it without passing my logger object? My extension is never called.

Below you may see the minimalistic build.gradle + snippet of code:

App.kt:

import mu.KLogger
import mu.KotlinLogging

private val log = KotlinLogging.logger {}

fun main() {
    log.info("log message",
            "key1" to "value1",
            "key2" to "value2"
    )
}

fun KLogger.info(message: String, vararg keyValues: Pair<String, Any?>) {
    log.info("log extension")
    info(message)
}

build.gradle.kts:

plugins {
    kotlin("jvm") version "1.3.72"
}

group = "rg"
version = "1.0"
java.sourceCompatibility = JavaVersion.VERSION_11

repositories {
    mavenCentral()
}

dependencies {
    implementation("org.jetbrains.kotlin:kotlin-reflect")
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
    implementation("ch.qos.logback:logback-classic:1.2.3")
    implementation("io.github.microutils:kotlin-logging:1.7.6")
}

Update: I end up with dropping extension idea and convert the existing code to a delegate.

fun structuredLogger(func: () -> Unit): StructuredLogger = StructuredLogger(func)

class StructuredLogger(func: () -> Unit, private val log: KLogger = KotlinLogging.logger(func)) : KLogger by log {

    fun info(msg: String?, vararg keyValues: Pair<LoggingKey, Any?>) {
        log.info(marker(*keyValues), msg)
    }

    // (...)
}

Solution

  • Logger has a function with the signature info(message: String, vararg arguments: Any) (as converted to Kotlin). Although yourvararg is for Pairs, that is just an ambiguous overload of Any. Extension functions cannot override non-extension functions and will simply be ignored if they do. You will have to change your function name or parameters.