7

Is there a way to implement something similar to Lombok's annotation @slf4j with annotation class in Kotlin?

Right now I have an extension function that instantiates a Logger Factory for me, and I must create these variables in each of my classes just like the example below:

@RestController
@RequestMapping("/api/v1/sample")
class SampleController() {
    private val log = logger()

    @GetMapping
    fun show(): String {
        log.info("SOME LOGGING MESSAGE")
        return "OK"
    }
}

inline fun <reified T> T.logger(): Logger {
    if (T::class.isCompanion) {
        return LoggerFactory.getLogger(T::class.java.enclosingClass)
    }
    return LoggerFactory.getLogger(T::class.java)
}

What I want to achieve is something like:

@Logger
@RestController
@RequestMapping("/api/v1/sample")
class SampleController() {
    @GetMapping
    fun show(): String {
        log.info("SOME LOGGING MESSAGE")
        return "OK"
    }
}
bpereira
  • 966
  • 2
  • 11
  • 29
  • Does it have to be an annotation? We use Kotlin Logging (https://github.com/MicroUtils/kotlin-logging) which allows for a static field to be placed right above the class definition: `private val logger = KotlinLogging.logger {}` Then you can use this logger in your class as you would want. – Danny Lagrouw May 25 '20 at 20:24

2 Answers2

7

made this pretty thing yesterday

@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
annotation class Log {
    companion object {
        inline var <reified T> T.log: Logger
            get() = LoggerFactory.getLogger(T::class.java)
            set(value) {}
    }
}
edit:

Don't use this mess above. use

companion object {
    private val log: Logger = LoggerFactory.getLogger(this::class.java)
}

see Idiomatic way of logging in Kotlin

Amund
  • 81
  • 1
  • 5
  • What is the reason why the first one doesn't work? – Francis Fredrick Valero Mar 23 '21 at 16:04
  • @FrancisFredrickValero it will work alright, but allows for AnyType.log() such that the mess it makes does not make up for it's accessability. Any class also has access to this method, so the annotation part is redundant – Amund Mar 26 '21 at 14:54
1

Turning Danny Lagrouw's comment into an answer:

You can get a similar to @Slf4j low-boilerplate solution that does not require you to specify the class manually by using Micro Utils' kotlin-logging

import mu.KotlinLogging

private val log = KotlinLogging.logger {}

class LoggingDemoClass() {

  fun logSometing() {
    log.info("Logging like a pro!")
  }
}

Caveat: I've only just started using it but and haven't investigated any of the kotlin sugar it puts on top of Slf4j but so far it seems to handle well enough as a drop-in replacement for @Slf4j in kotlin code.

NeilenMarais
  • 2,949
  • 1
  • 25
  • 23