From 9173fc046cc880a54e0857240224b1d66e31e0aa Mon Sep 17 00:00:00 2001 From: Marius Lewerenz Date: Mon, 1 Apr 2024 13:13:16 +0200 Subject: [PATCH] Allow supplying org.slf4j.Marker directly this fixes #360 --- .../kotlinlogging/slf4j/Slf4jExtensions.kt | 162 +++++++++++++++++- .../slf4j/internal/Slf4jMarker.kt | 6 + .../kotlinlogging/slf4j/Slf4jMarkerTest.kt | 75 ++++++++ 3 files changed, 238 insertions(+), 5 deletions(-) create mode 100644 src/javaMain/kotlin/io/github/oshai/kotlinlogging/slf4j/internal/Slf4jMarker.kt create mode 100644 src/jvmTest/kotlin/io/github/oshai/kotlinlogging/slf4j/Slf4jMarkerTest.kt diff --git a/src/javaMain/kotlin/io/github/oshai/kotlinlogging/slf4j/Slf4jExtensions.kt b/src/javaMain/kotlin/io/github/oshai/kotlinlogging/slf4j/Slf4jExtensions.kt index 71d2dced..521c8989 100644 --- a/src/javaMain/kotlin/io/github/oshai/kotlinlogging/slf4j/Slf4jExtensions.kt +++ b/src/javaMain/kotlin/io/github/oshai/kotlinlogging/slf4j/Slf4jExtensions.kt @@ -1,14 +1,19 @@ package io.github.oshai.kotlinlogging.slf4j -import io.github.oshai.kotlinlogging.KLogger -import io.github.oshai.kotlinlogging.KotlinLogging -import io.github.oshai.kotlinlogging.Level -import io.github.oshai.kotlinlogging.Marker +import io.github.oshai.kotlinlogging.* +import io.github.oshai.kotlinlogging.internal.toStringSafe import io.github.oshai.kotlinlogging.slf4j.internal.Slf4jLoggerFactory +import io.github.oshai.kotlinlogging.slf4j.internal.Slf4jMarker import org.slf4j.Logger import org.slf4j.MarkerFactory -public fun Marker.toSlf4j(): org.slf4j.Marker = MarkerFactory.getMarker(this.getName()) +public fun Marker.toSlf4j(): org.slf4j.Marker = + when (this) { + is Slf4jMarker -> marker + else -> MarkerFactory.getMarker(getName()) + } + +public fun org.slf4j.Marker.toKotlinLogging(): Marker = Slf4jMarker(this) public fun Level.toSlf4j(): org.slf4j.event.Level = when (this) { @@ -25,3 +30,150 @@ public fun KotlinLogging.logger(underlyingLogger: Logger): KLogger = Slf4jLoggerFactory.wrapJLogger(underlyingLogger) public fun Logger.toKLogger(): KLogger = KotlinLogging.logger(this) + +/** Lazy add a log message if isTraceEnabled is true */ +public fun KLogger.trace( + throwable: Throwable? = null, + marker: org.slf4j.Marker?, + message: () -> Any? +): Unit = + at(Level.TRACE, marker) { + this.message = message.toStringSafe() + this.cause = throwable + } + +/** Lazy add a log message if isDebugEnabled is true */ +public fun KLogger.debug( + throwable: Throwable? = null, + marker: org.slf4j.Marker?, + message: () -> Any? +): Unit = + at(Level.DEBUG, marker) { + this.message = message.toStringSafe() + this.cause = throwable + } + +/** Lazy add a log message if isInfoEnabled is true */ +public fun KLogger.info( + throwable: Throwable? = null, + marker: org.slf4j.Marker?, + message: () -> Any? +): Unit = + at(Level.INFO, marker) { + this.message = message.toStringSafe() + this.cause = throwable + } + +/** Lazy add a log message if isWarnEnabled is true */ +public fun KLogger.warn( + throwable: Throwable? = null, + marker: org.slf4j.Marker?, + message: () -> Any? +): Unit = + at(Level.WARN, marker) { + this.message = message.toStringSafe() + this.cause = throwable + } + +/** Lazy add a log message if isErrorEnabled is true */ +public fun KLogger.error( + throwable: Throwable? = null, + marker: org.slf4j.Marker?, + message: () -> Any? +): Unit = + at(Level.ERROR, marker) { + this.message = message.toStringSafe() + this.cause = throwable + } + +/** Lazy add a log message with throwable payload if isTraceEnabled is true */ +public fun KLogger.atTrace( + marker: org.slf4j.Marker?, + block: KLoggingEventBuilder.() -> Unit +): Unit = at(Level.TRACE, marker, block) + +/** Lazy add a log message with throwable payload if isDebugEnabled is true */ +public fun KLogger.atDebug( + marker: org.slf4j.Marker?, + block: KLoggingEventBuilder.() -> Unit +): Unit = at(Level.DEBUG, marker, block) + +/** Lazy add a log message with throwable payload if isInfoEnabled is true */ +public fun KLogger.atInfo(marker: org.slf4j.Marker?, block: KLoggingEventBuilder.() -> Unit): Unit = + at(Level.INFO, marker, block) + +/** Lazy add a log message with throwable payload if isWarnEnabled is true */ +public fun KLogger.atWarn(marker: org.slf4j.Marker?, block: KLoggingEventBuilder.() -> Unit): Unit = + at(Level.WARN, marker, block) + +/** Lazy add a log message with throwable payload if isErrorEnabled is true */ +public fun KLogger.atError( + marker: org.slf4j.Marker?, + block: KLoggingEventBuilder.() -> Unit +): Unit = at(Level.ERROR, marker, block) + +/** Lazy add a log message if level enabled */ +public fun KLogger.at( + level: Level, + marker: org.slf4j.Marker? = null, + block: KLoggingEventBuilder.() -> Unit +) { + at(level, marker?.toKotlinLogging(), block) +} + +/** + * Similar to [.isTraceEnabled] method except that the marker data is also taken into account. + * + * @param marker The marker data to take into consideration + * @return True if this Logger is enabled for the TRACE level, false otherwise. + */ +public fun KLogger.isTraceEnabled(marker: org.slf4j.Marker? = null): Boolean = + isLoggingEnabledFor(Level.TRACE, marker) + +/** + * Similar to [.isDebugEnabled] method except that the marker data is also taken into account. + * + * @param marker The marker data to take into consideration + * @return True if this Logger is enabled for the DEBUG level, false otherwise. + */ +public fun KLogger.isDebugEnabled(marker: org.slf4j.Marker? = null): Boolean = + isLoggingEnabledFor(Level.DEBUG, marker) + +/** + * Similar to [.isInfoEnabled] method except that the marker data is also taken into consideration. + * + * @param marker The marker data to take into consideration + * @return true if this Logger is enabled for the INFO level, false otherwise. + */ +public fun KLogger.isInfoEnabled(marker: org.slf4j.Marker? = null): Boolean = + isLoggingEnabledFor(Level.INFO, marker) + +/** + * Similar to [.isWarnEnabled] method except that the marker data is also taken into consideration. + * + * @param marker The marker data to take into consideration + * @return True if this Logger is enabled for the WARN level, false otherwise. + */ +public fun KLogger.isWarnEnabled(marker: org.slf4j.Marker? = null): Boolean = + isLoggingEnabledFor(Level.WARN, marker) + +/** + * Similar to [.isErrorEnabled] method except that the marker data is also taken into consideration. + * + * @param marker The marker data to take into consideration + * @return True if this Logger is enabled for the ERROR level, false otherwise. + */ +public fun KLogger.isErrorEnabled(marker: org.slf4j.Marker? = null): Boolean = + isLoggingEnabledFor(Level.ERROR, marker) + +/** + * Similar to [.isLoggingOff] method except that the marker data is also taken into consideration. + * + * @param marker The marker data to take into consideration + * @return True if this Logger is set to the OFF level, false otherwise. + */ +public fun KLogger.isLoggingOff(marker: org.slf4j.Marker? = null): Boolean = + !isLoggingEnabledFor(Level.ERROR, marker) + +public fun KLogger.isLoggingEnabledFor(level: Level, marker: org.slf4j.Marker? = null): Boolean = + isLoggingEnabledFor(level, marker?.toKotlinLogging()) diff --git a/src/javaMain/kotlin/io/github/oshai/kotlinlogging/slf4j/internal/Slf4jMarker.kt b/src/javaMain/kotlin/io/github/oshai/kotlinlogging/slf4j/internal/Slf4jMarker.kt new file mode 100644 index 00000000..a767427e --- /dev/null +++ b/src/javaMain/kotlin/io/github/oshai/kotlinlogging/slf4j/internal/Slf4jMarker.kt @@ -0,0 +1,6 @@ +package io.github.oshai.kotlinlogging.slf4j.internal + +import io.github.oshai.kotlinlogging.Marker + +@JvmInline +internal value class Slf4jMarker(val marker: org.slf4j.Marker) : Marker, org.slf4j.Marker by marker diff --git a/src/jvmTest/kotlin/io/github/oshai/kotlinlogging/slf4j/Slf4jMarkerTest.kt b/src/jvmTest/kotlin/io/github/oshai/kotlinlogging/slf4j/Slf4jMarkerTest.kt new file mode 100644 index 00000000..8b7aaecb --- /dev/null +++ b/src/jvmTest/kotlin/io/github/oshai/kotlinlogging/slf4j/Slf4jMarkerTest.kt @@ -0,0 +1,75 @@ +package io.github.oshai.kotlinlogging.slf4j + +import io.github.oshai.kotlinlogging.KotlinLogging +import io.github.oshai.kotlinlogging.addAppender +import io.github.oshai.kotlinlogging.removeAppender +import kotlin.test.assertEquals +import org.apache.logging.log4j.core.Appender +import org.apache.logging.log4j.core.LogEvent +import org.apache.logging.log4j.core.appender.NullAppender +import org.apache.logging.slf4j.Log4jMarker +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test + +private val logger = KotlinLogging.logger {} + +private class TestAppender( + val appender: Appender = NullAppender.createAppender("testAppender"), + var lastEvent: LogEvent? = null, +) : Appender by appender { + override fun append(event: LogEvent) { + lastEvent = event.toImmutable() + appender.append(event) + } +} + +class Slf4jMarkerTest { + + private val testAppender = TestAppender() + + @BeforeEach + fun setupAppender() { + addAppender(testAppender) + } + + @AfterEach + fun removeAppender() { + removeAppender(testAppender) + } + + @Test + fun `a slf4j Marker can be directly supplied to the logger`() { + + val log4jMarker = + object : org.apache.logging.log4j.Marker { + override fun addParents( + vararg markers: org.apache.logging.log4j.Marker? + ): org.apache.logging.log4j.Marker = TODO("Not yet implemented") + + override fun getName(): String = "foo" + + override fun getParents(): Array = + TODO("Not yet implemented") + + override fun hasParents(): Boolean = false + + override fun isInstanceOf(m: org.apache.logging.log4j.Marker?): Boolean = false + + override fun isInstanceOf(name: String?): Boolean = false + + override fun remove(marker: org.apache.logging.log4j.Marker?): Boolean = + TODO("Not yet implemented") + + override fun setParents( + vararg markers: org.apache.logging.log4j.Marker? + ): org.apache.logging.log4j.Marker = TODO("Not yet implemented") + } + + val slf4jMarker = Log4jMarker(null, log4jMarker) + + logger.atError(slf4jMarker) { message = "bar" } + + assertEquals(testAppender.lastEvent?.marker, log4jMarker) + } +}