CCCPaste

KMP Logger

// file: app/src/commonMain/kotlin/eu/torvian/chatbot/app/utils/misc/KmpLogger.kt
package eu.torvian.chatbot.app.utils.misc

/**
 * Common logging interface for Kotlin Multiplatform.
 * This interface defines the logging API available in common code.
 * Each platform will provide its actual implementation.
 */
interface KmpLogger {
    fun trace(message: String, throwable: Throwable? = null)
    fun debug(message: String, throwable: Throwable? = null)
    fun info(message: String, throwable: Throwable? = null)
    fun warn(message: String, throwable: Throwable? = null)
    fun error(message: String, throwable: Throwable? = null)
    fun fatal(message: String, throwable: Throwable? = null)
}

/**
 * Expected top-level function that acts as a factory for [KmpLogger] instances.
 * Each platform will provide an 'actual' implementation of this function.
 *
 * This is the most stable and recommended approach for platform-specific utilities
 * when avoiding DI framework boilerplate in every consuming class and ensuring
 * compatibility with parallel test execution.
 */
expect fun createKmpLogger(tag: String): KmpLogger

/**
 * Helper function to easily get a [KmpLogger] instance for a class.
 * This function uses the platform-specific `createKmpLogger` factory function.
 *
 * Usage: `private val logger = kmpLogger()`
 */
inline fun  kmpLogger(): KmpLogger {
    return createKmpLogger(T::class.simpleName ?: "Unknown")
}

// file: app/src/androidMain/kotlin/eu/torvian/chatbot/app/utils/misc/KmpLogger.android.kt
package eu.torvian.chatbot.app.utils.misc

import android.util.Log

/**
 * Actual implementation of [KmpLogger] for the Android target, using Android's Log API.
 */
class AndroidKmpLogger(private val tag: String) : KmpLogger {
    override fun trace(message: String, throwable: Throwable?) {
        Log.v(tag, message, throwable)
    }

    override fun debug(message: String, throwable: Throwable?) {
        Log.d(tag, message, throwable)
    }

    override fun info(message: String, throwable: Throwable?) {
        Log.i(tag, message, throwable)
    }

    override fun warn(message: String, throwable: Throwable?) {
        Log.w(tag, message, throwable)
    }

    override fun error(message: String, throwable: Throwable?) {
        Log.e(tag, message, throwable)
    }

    override fun fatal(message: String, throwable: Throwable?) {
        Log.wtf(tag, message, throwable)
    }
}

/**
 * Actual implementation of the [createKmpLogger] factory function for the Android target.
 * This function provides [AndroidKmpLogger] instances.
 */
actual fun createKmpLogger(tag: String): KmpLogger {
    return AndroidKmpLogger(tag)
}



// file: app/src/desktopMain/kotlin/eu/torvian/chatbot/app/utils/misc/createKmpLogger.desktop.kt
package eu.torvian.chatbot.app.utils.misc

import org.apache.logging.log4j.LogManager

/**
 * Actual implementation of [KmpLogger] for the JVM (Desktop) target, using Log4j2.
 */
class DesktopKmpLogger(private val tag: String) : KmpLogger {
    private val logger = LogManager.getLogger(tag)

    override fun trace(message: String, throwable: Throwable?) {
        logger.trace(message, throwable)
    }

    override fun debug(message: String, throwable: Throwable?) {
        logger.debug(message, throwable)
    }

    override fun info(message: String, throwable: Throwable?) {
        logger.info(message, throwable)
    }

    override fun warn(message: String, throwable: Throwable?) {
        logger.warn(message, throwable)
    }

    override fun error(message: String, throwable: Throwable?) {
        logger.error(message, throwable)
    }

    override fun fatal(message: String, throwable: Throwable?) {
        logger.fatal(message, throwable)
    }
}

/**
 * Actual implementation of the [createKmpLogger] factory function for the JVM (Desktop) target.
 * This function provides [DesktopKmpLogger] instances.
 */
actual fun createKmpLogger(tag: String): KmpLogger {
    return DesktopKmpLogger(tag)
}

// file: app/src/wasmJsMain/kotlin/eu/torvian/chatbot/app/utils/misc/createKmpLogger.wasmJs.kt
package eu.torvian.chatbot.app.utils.misc

/**
 * A simplified external interface for the browser's Console API, compatible with Kotlin/Wasm.
 * It explicitly uses String for arguments, as per Wasm JS interop rules.
 *
 * Console methods typically take a primary message and then optional additional arguments.
 * We model this by having a `message: String` and `vararg optionalParams: String`.
 */
external interface Console {
    // Note: The actual JS console functions take Any, but for Wasm interop,
    // we limit it to String as that's what we primarily pass.
    fun debug(message: String, vararg optionalParams: String)
    fun info(message: String, vararg optionalParams: String)
    fun warn(message: String, vararg optionalParams: String)
    fun error(message: String, vararg optionalParams: String)
}

/**
 * The global browser `console` object.
 * Declared 'external val' to indicate it's a JavaScript global variable.
 */
external val console: Console

/**
 * Actual implementation of [KmpLogger] for the Kotlin/Wasm (JavaScript) target,
 * using the browser's `console` API.
 */
class WasmKmpLogger(private val tag: String) : KmpLogger {
    override fun trace(message: String, throwable: Throwable?) {
        if (throwable != null) {
            console.debug("[$tag] $message ${throwable.stackTraceToString()}")
        } else {
            console.debug("[$tag] $message")
        }
    }

    override fun debug(message: String, throwable: Throwable?) {
        if (throwable != null) {
            console.debug("[$tag] $message ${throwable.stackTraceToString()}")
        } else {
            console.debug("[$tag] $message")
        }
    }

    override fun info(message: String, throwable: Throwable?) {
        if (throwable != null) {
            console.info("[$tag] $message ${throwable.stackTraceToString()}")
        } else {
            console.info("[$tag] $message")
        }
    }

    override fun warn(message: String, throwable: Throwable?) {
        if (throwable != null) {
            console.warn("[$tag] $message ${throwable.stackTraceToString()}")
        } else {
            console.warn("[$tag] $message")
        }
    }

    override fun error(message: String, throwable: Throwable?) {
        if (throwable != null) {
            console.error("[$tag] $message ${throwable.stackTraceToString()}")
        } else {
            console.error("[$tag] $message")
        }
    }

    override fun fatal(message: String, throwable: Throwable?) {
        if (throwable != null) {
            console.error("[$tag] $message ${throwable.stackTraceToString()}")
        } else {
            console.error("[$tag] $message")
        }
    }
}

/**
 * Actual implementation of the [createKmpLogger] factory function for the Kotlin/Wasm (JavaScript) target.
 * This function provides [WasmKmpLogger] instances.
 */
actual fun createKmpLogger(tag: String): KmpLogger {
    return WasmKmpLogger(tag)
}