From 5594aa9b28a22fc06d9251a47ae3feacd40b45aa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 3 May 2026 11:51:43 +0000 Subject: [PATCH 1/4] Initial plan From e93a9e7e1c634bef57b91ba215676fa8b8984855 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 3 May 2026 11:58:15 +0000 Subject: [PATCH 2/4] Fix native build error: update GraalVM substitution onlyWith condition to check if target class exists Agent-Logs-Url: https://github.com/oshai/kotlin-logging/sessions/728f006b-d368-4f73-92f3-ca9855e1798f Co-authored-by: oshai <2683969+oshai@users.noreply.github.com> --- ...i_kotlinlogging_internal_KLoggerFactory.kt | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/jvmMain/kotlin/io/github/oshai/kotlinlogging/internal/Target_io_github_oshai_kotlinlogging_internal_KLoggerFactory.kt b/src/jvmMain/kotlin/io/github/oshai/kotlinlogging/internal/Target_io_github_oshai_kotlinlogging_internal_KLoggerFactory.kt index aa8698de..80ce0426 100644 --- a/src/jvmMain/kotlin/io/github/oshai/kotlinlogging/internal/Target_io_github_oshai_kotlinlogging_internal_KLoggerFactory.kt +++ b/src/jvmMain/kotlin/io/github/oshai/kotlinlogging/internal/Target_io_github_oshai_kotlinlogging_internal_KLoggerFactory.kt @@ -19,7 +19,7 @@ import java.util.function.BooleanSupplier internal class Target_io_github_oshai_kotlinlogging_internal_KLoggerFactory { @TargetClass( className = "io.github.oshai.kotlinlogging.internal.KLoggerFactory", - onlyWith = [LogbackNotOnClasspath::class], + onlyWith = [KLoggerFactoryExistsAndLogbackNotOnClasspath::class], ) companion object { @Substitute @@ -35,8 +35,25 @@ internal class Target_io_github_oshai_kotlinlogging_internal_KLoggerFactory { } } -internal class LogbackNotOnClasspath : BooleanSupplier { +/** + * Condition that returns true only when: + * 1. The substitution target class (`io.github.oshai.kotlinlogging.internal.KLoggerFactory`) + * actually exists on the classpath (it was removed in v8.x), AND + * 2. Logback is not on the classpath. + * + * This prevents a GraalVM native image build error when the target class no longer exists. See + * [https://github.com/oshai/kotlin-logging/issues/385]. + */ +internal class KLoggerFactoryExistsAndLogbackNotOnClasspath : BooleanSupplier { override fun getAsBoolean(): Boolean { + // First check if the substitution target class exists (it doesn't in v8.x+). + // If it doesn't exist, the substitution must be inactive to avoid a native build error. + try { + Class.forName("io.github.oshai.kotlinlogging.internal.KLoggerFactory") + } catch (_: ClassNotFoundException) { + return false + } + // Target class exists; only apply substitution when Logback is not on the classpath. try { Class.forName("ch.qos.logback.classic.LoggerContext") return false From 5b822c2d2cac171e2aff03f3540cfda106b6364e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 3 May 2026 12:11:23 +0000 Subject: [PATCH 3/4] Fix native build error: update GraalVM substitution to target KotlinLoggingConfiguration Agent-Logs-Url: https://github.com/oshai/kotlin-logging/sessions/fb12ce1d-eadb-48ae-8d8f-8cf8962c1db4 Co-authored-by: oshai <2683969+oshai@users.noreply.github.com> --- ...otlinlogging_KotlinLoggingConfiguration.kt | 47 ++++++++++++++ ...i_kotlinlogging_internal_KLoggerFactory.kt | 64 ------------------- 2 files changed, 47 insertions(+), 64 deletions(-) create mode 100644 src/jvmMain/kotlin/io/github/oshai/kotlinlogging/internal/Target_io_github_oshai_kotlinlogging_KotlinLoggingConfiguration.kt delete mode 100644 src/jvmMain/kotlin/io/github/oshai/kotlinlogging/internal/Target_io_github_oshai_kotlinlogging_internal_KLoggerFactory.kt diff --git a/src/jvmMain/kotlin/io/github/oshai/kotlinlogging/internal/Target_io_github_oshai_kotlinlogging_KotlinLoggingConfiguration.kt b/src/jvmMain/kotlin/io/github/oshai/kotlinlogging/internal/Target_io_github_oshai_kotlinlogging_KotlinLoggingConfiguration.kt new file mode 100644 index 00000000..e35b6cdf --- /dev/null +++ b/src/jvmMain/kotlin/io/github/oshai/kotlinlogging/internal/Target_io_github_oshai_kotlinlogging_KotlinLoggingConfiguration.kt @@ -0,0 +1,47 @@ +package io.github.oshai.kotlinlogging.internal + +import com.oracle.svm.core.annotate.Substitute +import com.oracle.svm.core.annotate.TargetClass +import com.oracle.svm.core.annotate.TargetElement +import io.github.oshai.kotlinlogging.KLoggerFactory +import io.github.oshai.kotlinlogging.jul.internal.JulLoggerFactory +import io.github.oshai.kotlinlogging.slf4j.internal.Slf4jLoggerFactory +import java.util.function.BooleanSupplier + +/** + * This class is a substitution class as described in + * [https://build-native-java-apps.cc/developer-guide/substitution/]. It fixes an issue where the + * native build (GraalVM native-image) fails if Logback is not on the classpath. See + * [https://github.com/oshai/kotlin-logging/issues/465]. The weird-looking class name is according + * to convention. + */ +@Suppress("unused") +internal class Target_io_github_oshai_kotlinlogging_KotlinLoggingConfiguration { + @TargetClass( + className = "io.github.oshai.kotlinlogging.KotlinLoggingConfiguration", + onlyWith = [LogbackNotOnClasspath::class], + ) + companion object { + @Substitute + @TargetElement(name = "detectLogger") + fun detectLogger(): KLoggerFactory { + if (System.getProperty("kotlin-logging-to-jul") != null) { + return JulLoggerFactory + } + // Intentionally leave out the logback branch as logback is not on the classpath. + // default to SLF4J + return Slf4jLoggerFactory + } + } +} + +internal class LogbackNotOnClasspath : BooleanSupplier { + override fun getAsBoolean(): Boolean { + try { + Class.forName("ch.qos.logback.classic.LoggerContext") + return false + } catch (_: ClassNotFoundException) { + return true + } + } +} diff --git a/src/jvmMain/kotlin/io/github/oshai/kotlinlogging/internal/Target_io_github_oshai_kotlinlogging_internal_KLoggerFactory.kt b/src/jvmMain/kotlin/io/github/oshai/kotlinlogging/internal/Target_io_github_oshai_kotlinlogging_internal_KLoggerFactory.kt deleted file mode 100644 index 80ce0426..00000000 --- a/src/jvmMain/kotlin/io/github/oshai/kotlinlogging/internal/Target_io_github_oshai_kotlinlogging_internal_KLoggerFactory.kt +++ /dev/null @@ -1,64 +0,0 @@ -package io.github.oshai.kotlinlogging.internal - -import com.oracle.svm.core.annotate.Substitute -import com.oracle.svm.core.annotate.TargetClass -import com.oracle.svm.core.annotate.TargetElement -import io.github.oshai.kotlinlogging.KLogger -import io.github.oshai.kotlinlogging.jul.internal.JulLoggerFactory -import io.github.oshai.kotlinlogging.slf4j.internal.Slf4jLoggerFactory -import java.util.function.BooleanSupplier - -/** - * This class is a substitution class as described in - * [https://build-native-java-apps.cc/developer-guide/substitution/]. It fixes an issue where the - * native build (GraalVM native-image) fails if Logback is not on the classpath. See - * [https://github.com/oshai/kotlin-logging/issues/465]. The weird-looking class name is according - * to convention. - */ -@Suppress("unused") -internal class Target_io_github_oshai_kotlinlogging_internal_KLoggerFactory { - @TargetClass( - className = "io.github.oshai.kotlinlogging.internal.KLoggerFactory", - onlyWith = [KLoggerFactoryExistsAndLogbackNotOnClasspath::class], - ) - companion object { - @Substitute - @TargetElement(name = "logger\$kotlin_logging") - fun logger(name: String): KLogger { - if (System.getProperty("kotlin-logging-to-jul") != null) { - return JulLoggerFactory.wrapJLogger(JulLoggerFactory.jLogger(name)) - } - // Intentionally leave out the logback branch as logback is not on the classpath. - // default to SLF4J - return Slf4jLoggerFactory.wrapJLogger(Slf4jLoggerFactory.jLogger(name)) - } - } -} - -/** - * Condition that returns true only when: - * 1. The substitution target class (`io.github.oshai.kotlinlogging.internal.KLoggerFactory`) - * actually exists on the classpath (it was removed in v8.x), AND - * 2. Logback is not on the classpath. - * - * This prevents a GraalVM native image build error when the target class no longer exists. See - * [https://github.com/oshai/kotlin-logging/issues/385]. - */ -internal class KLoggerFactoryExistsAndLogbackNotOnClasspath : BooleanSupplier { - override fun getAsBoolean(): Boolean { - // First check if the substitution target class exists (it doesn't in v8.x+). - // If it doesn't exist, the substitution must be inactive to avoid a native build error. - try { - Class.forName("io.github.oshai.kotlinlogging.internal.KLoggerFactory") - } catch (_: ClassNotFoundException) { - return false - } - // Target class exists; only apply substitution when Logback is not on the classpath. - try { - Class.forName("ch.qos.logback.classic.LoggerContext") - return false - } catch (_: ClassNotFoundException) { - return true - } - } -} From c634b5436483f148fded1b5a9d38258fd234d8d9 Mon Sep 17 00:00:00 2001 From: Ohad Shai Date: Sun, 3 May 2026 15:36:34 +0300 Subject: [PATCH 4/4] Fix GraalVM substitution to preserve kotlin-logging-to-direct behavior --- ...io_github_oshai_kotlinlogging_KotlinLoggingConfiguration.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/jvmMain/kotlin/io/github/oshai/kotlinlogging/internal/Target_io_github_oshai_kotlinlogging_KotlinLoggingConfiguration.kt b/src/jvmMain/kotlin/io/github/oshai/kotlinlogging/internal/Target_io_github_oshai_kotlinlogging_KotlinLoggingConfiguration.kt index e35b6cdf..873943f4 100644 --- a/src/jvmMain/kotlin/io/github/oshai/kotlinlogging/internal/Target_io_github_oshai_kotlinlogging_KotlinLoggingConfiguration.kt +++ b/src/jvmMain/kotlin/io/github/oshai/kotlinlogging/internal/Target_io_github_oshai_kotlinlogging_KotlinLoggingConfiguration.kt @@ -3,6 +3,7 @@ package io.github.oshai.kotlinlogging.internal import com.oracle.svm.core.annotate.Substitute import com.oracle.svm.core.annotate.TargetClass import com.oracle.svm.core.annotate.TargetElement +import io.github.oshai.kotlinlogging.DirectLoggerFactory import io.github.oshai.kotlinlogging.KLoggerFactory import io.github.oshai.kotlinlogging.jul.internal.JulLoggerFactory import io.github.oshai.kotlinlogging.slf4j.internal.Slf4jLoggerFactory @@ -27,6 +28,8 @@ internal class Target_io_github_oshai_kotlinlogging_KotlinLoggingConfiguration { fun detectLogger(): KLoggerFactory { if (System.getProperty("kotlin-logging-to-jul") != null) { return JulLoggerFactory + } else if (System.getProperty("kotlin-logging-to-direct") == "true") { + return DirectLoggerFactory } // Intentionally leave out the logback branch as logback is not on the classpath. // default to SLF4J