2

I'm using kotlin-logging (https://github.com/MicroUtils/kotlin-logging), I want my logger to print to subclass name instead of abstract class name. Example I have these class

// in A.kt file:

import mu.KotlinLogging

private val logger = KotlinLogging.logger {}

abstract class A<T> {
    fun someMethod(item: T?) {
        logger.info("testing")
    }
}



fun main() {
    val b: A<String> = B()
    b.someMethod("123")
}




// in B.kt file

import mu.KotlinLogging

private val logger = KotlinLogging.logger {}

class B : A<String>() {
}

It prints: [main] INFO A - testing

But I want it to print: [main] INFO B - testing (where B is the subclass name)

Timothy
  • 55
  • 1
  • 5
  • It is usually a better practice to print the abstract class because logger should indicate the place the log was printed clearly. – oshai Feb 15 '20 at 18:23

2 Answers2

3

You may want to send the logger to the abstract class.

// in A.kt file:

import mu.KotlinLogging

abstract class A<T>(private val logger: KLogger) {
    fun someMethod(item: T?) {
        logger.info("testing")
    }
}



fun main() {
    val b: A<String> = B()
    b.someMethod("123")
}




// in B.kt file

import mu.KotlinLogging

private val logger = KotlinLogging.logger {}

class B : A<String>(logger) {
}

Result: [main] INFO B - testing

Animesh Sahu
  • 7,445
  • 2
  • 21
  • 49
3

If the logger were inside of your abstract Class A, you could use the logger(name: String) method instead of the logger(func: () -> Unit) method like so:

// in A.kt file

import mu.KotlinLogging

abstract class A<T> {
    private val logger = KotlinLogging.logger("${this::class.java.name}")

    fun someMethod(item: T?) {
        logger.info("testing")
    }
}

fun main() {
    val b: A<String> = B()
    b.someMethod("123")
}

// in B.kt file

class B : A<String>() {
}

So that any class that extends A would be logged according to its own class name.

Result: INFO B - testing

Why? KotlinLogging has two methods, one using the logger(name: String) and one using logger(func: () -> Unit) found here: https://github.com/MicroUtils/kotlin-logging/blob/master/src/jvmMain/kotlin/mu/KotlinLogging.kt#L14-L16

The logger(func: () -> Unit) calls the logger(name: String) internally using the class name of the function: https://github.com/MicroUtils/kotlin-logging/blob/master/src/jvmMain/kotlin/mu/internal/KLoggerFactory.kt#L29-L30

In your case, the function call in A.kt is private val logger = KotlinLogging.logger {} is from inside A.kt, never outside that file, so it will always be from A. so it finds A in this name resolver: https://github.com/MicroUtils/kotlin-logging/blob/master/src/jvmMain/kotlin/mu/internal/KLoggerNameResolver.kt#L15-L23

If we use this code here:

import mu.KotlinLogging

private val funcJavaClass: String = {}.javaClass.name

abstract class A<T> {
    private val logger = KotlinLogging.logger("${this::class.java.name}")

    fun someMethod(item: T?) {
        logger.info("$funcJavaClass")
        logger.info("testing")
    }
}

the result is AKt$funcJavaClass$1 so when we slice the name here: https://github.com/MicroUtils/kotlin-logging/blob/master/src/jvmMain/kotlin/mu/internal/KLoggerNameResolver.kt#L18 the result is simply A

It's also worth noting that the original example uses A because the file name is A, not because of the class.

// in R.kt

import mu.KotlinLogging

private val funcJavaClass: String = {}.javaClass.name

abstract class A<T> {
    private val logger = KotlinLogging.logger("${this::class.java.name}")

    fun someMethod(item: T?) {
        logger.info("$funcJavaClass")
        logger.info("testing")
    }
}

result: RKt$funcJavaClass$1

whereas if the function is called from inside the class

// in R.kt

import mu.KotlinLogging

abstract class A<T> {
    private val logger = KotlinLogging.logger("${this::class.java.name}")
    private val funcJavaClass: String = {}.javaClass.name

    fun someMethod(item: T?) {
        logger.info("$funcJavaClass")
        logger.info("testing")
    }
}

result: A$funcJavaClass$1

Dave K
  • 31
  • 3