GitHub user mcmacker4 created a discussion: No use of `inline` in `log4j-api-kotlin`?
As a preface, i will say that i am writing this here but I am not entirely sure that this is the appropriate forum. It looks to me as if `log4j-api-kotlin` is an independent project based on the fact that it is hosted in a [different github repo](https://github.com/apache/logging-log4j-kotlin) and it is not included in `log4j-bom`. **If this is not the correct forum, I would appreciate being pointed in the right direction**. I didn't want to open an actual github issue in the repo before even discussing this somewhere, but that repo doesn't have discussions enabled, so I will use this one as fallback. --- While i was experimenting with reactive spring, i added log4j's kotlin api, which is supposed to use kotlin's super cool powers to make `log4j` more kotlin idiomatic by moving lambdas to the last argument and promoting string templates instead of log4j's template arguments. Another of kotlin's powers is function call inlining. What i noticed, though, is that none of the lambda based functions in `KotlinLogger` are inline. **Was this discussed at any point?** I cannot find any discussion or issues related to this topic. Designing KotlinLogger's lambda based functions to be inline would allow things like suspending in the middle of the lambda. It might also make these logs I noticed this quirk when i wanted to log the current coroutine context. The function `currentCoroutineContext()` from `kotlinx-coroutines` is a suspending function, but the following code will not compile: ```kotlin // this would be in a class suspend fun fetchUser() { // logger is defined in the companion object, as recommended in the docs logger.info { "Context: ${currentCoroutineContext()" } ^ compiler error } ``` The problem here is that, since the lambda passed to the `info()` method is neither `suspend` nor inlined, you cannot call a suspending function inside that lambda. Marking the lambda as `suspend` would not allow use in regular non-`suspend` code. This is because the implementation delegates to `logIfEnabled`, turning the lambda reference into a `org.apache.logging.log4j.util.Supplier`. On the other hand, if the `info()` method was redesigned to allow inlining, the error would disappear. See this simple example: ```kotlin inline fun info(supplier: () -> String) { if (delegate.isInfoEnabled) delegate.info(supplier()) } ``` With this change, the method call would be translated into the if statement in the method body, and the call to the lambda would also be inlined. This function: ```kotlin fun main() { val logger = logger("com.example") logger.inlineInfo { "Message: ${expensiveOperation()}" } } ``` Compiles into this code (decompiled with fernflower, slightly cleaned up for readability) ```java public static final void main() { KotlinLogger logger = LoggingFactoryKt.logger("com.example"); if (logger.getDelegate().isInfoEnabled()) { ExtendedLogger delegate = logger.getDelegate(); delegate.info("Message: " + expensiveOperation()); } } ``` As you can see, the call to `expensiveOperation()` happens directly in `main`, but only if the `info` level is enabled. What this means is that now, if the call site is a suspend function, you can call a suspend function in the lambda and, after compilation, it would be called directly in the suspend function, which is legal, so the first code block in this post (the one that failed to compile when calling `currentCoroutineContext()`) would compile and work just fine. GitHub link: https://github.com/apache/logging-log4j2/discussions/4146 ---- This is an automatically sent email for [email protected]. To unsubscribe, please send an email to: [email protected]
