Skip to main content Skip to docs navigation

Document not reviewed yet, might be outdated. Please, let us know if you find something invalid here.
To access this functionality you can include the: com.soywiz.korge:korge-foundation:5.1.0 artifact from maven central. All the functionality yields in the korlibs.logger package .
On this page

This module provides a simple interface to do logging into suitable outputs like javascript’s console or stdout/stderr.

Console

Klogger provides a common way for logging into JavaScript console with fallback to stdout and stderr.

object Console {
    fun error(vararg msg: Any?): Unit
    fun log(vararg msg: Any?): Unit
}

Logging

Klogger provides a simple yet configurable interface for logging.

// Logger construction (returns the same instance for the same name)
fun Logger(name: String)

// Default Level and output for loggers that do not define this
var Logger.Companion.defaultLevel: Level?
var Logger.Companion.defaultOutput: Output

class Logger {
    // Output for this logger
    var output: Output
    fun setOutput(output: Logger.Output): Logger
    val isLocalOutputSet: Boolean

    // Log level for this logger
    var level: Level
    val isLocalLevelSet: Boolean
    fun setLevel(level: Logger.Level): Logger
    fun isEnabled(level: Level): Boolean
    inline val isFatalEnabled: Boolean
    inline val isErrorEnabled: Boolean
    inline val isWarnEnabled: Boolean
    inline val isInfoEnabled: Boolean
    inline val isDebugEnabled: Boolean
    inline val isTraceEnabled: Boolean

    // Emit logs
    inline fun log(level: Level, msg: () -> Any?)
    inline fun fatal(msg: () -> Any?)
    inline fun error(msg: () -> Any?)
    inline fun warn(msg: () -> Any?)
    inline fun info(msg: () -> Any?)
    inline fun debug(msg: () -> Any?)
    inline fun trace(msg: () -> Any?)
}

enum class Logger.Level(val index: Int) {
    NONE(0), FATAL(1), ERROR(2),
    WARN(3), INFO(4), DEBUG(5), TRACE(6)
}

interface Logger.Output {
    fun output(logger: Logger, level: Logger.Level, msg: Any?)
}

object Logger.ConsoleLogOutput : Logger.Output

Externally configuring loggers

Since klogger does not have dependencies, by default it doesn’t configure the loggers from any config file or environment. But here you have some ideas for configuring the loggers without recompiling:

fun configureLoggerFromProperties(str: String) {
	val props = Props.load(str)
	for ((key, value) in props) {
		try {
			Logger(key).level = Logger.Level.valueOf(value.toUpperCase())
		} catch (e: Throwable) {
			e.printStackTrace()
		}
	}
}

suspend fun configureLoggerFromProperties(file: VfsFile) {
	println("configureLoggerFromProperties:")
	try {
		configureLoggerFromProperties(file.readString())
	} catch (e: Throwable) {
		println("Couldn't load Klogger configuration $file : ${e.message}")
	}
}


private class Props(private val props: LinkedHashMap<String, String> = LinkedHashMap<String, String>()) : MutableMap<String, String> by props {
	companion object {
		fun load(str: String) = Props().apply { deserializeNew(str) }
	}

	fun deserializeAdd(str: String) {
		for (line in str.split("\n")) {
			if (line.startsWith('#')) continue
			if (line.isBlank()) continue
			val parts = line.split('=', limit = 2)
			val key = parts[0].trim()
			val value = parts.getOrElse(1) { " " }.trim()
			props[key] = value
		}
	}

	fun deserializeNew(str: String) {
		clear()
		deserializeAdd(str)
	}

	fun serialize(): String = props.map { "${it.key}=${it.value}" }.joinToString("\n")
}

private suspend fun VfsFile.loadProperties(charset: Charset = UTF8) = Props.load(this.readString(charset))
private suspend fun VfsFile.saveProperties(props: Props, charset: Charset = UTF8) = this.writeString(props.serialize(), charset = charset)

AnsiEscape

Klogger exposes functionality to generate AnsiEscape escape sequences:

Bold, Underlined & reversed:

You can set the bold, underlined and reversed attributes:

val boldStr: String = AnsiEscape { "this is bold".bold } 
val underlineStr: String = AnsiEscape { "this is underlined".underline } 
val reversedStr: String = AnsiEscape { "this is reversed".colorReversed } 
val allStr: String = AnsiEscape { "this is ${"heavy".bold}".underline.colorReversed } 

Simple colors:

You can access to the enum: Color.BLACK, Color.RED, Color.GREEN, Color.YELLOW, Color.BLUE, Color.PURPLE, Color.CYAN, Color.WHITE Then use the method String.color(Color.RED, bright = true) or String.bgColor(Color.GREEN, bright = false). But AnsiEscape also provide property shortcuts like: String.black, String.red… or String.bgYellow, String.bgCyan etc.

val mixedStr: String = AnsiEscape { "this is red".red + ", blue".blue + ", green".green } 
val mixedStr2: String = AnsiEscape { "this is cyan with a yellow background".cyan.bgYellow } 
val mixedStr3: String = AnsiEscape { "today is brigther".color(AnsiEscape.Color.GREEN, bright = true).bgColor(AnsiEscape.Color.PURPLE, bright = true) } 

Simple Usage

By calling AnsiEscape {} you have access inside to some extension properties for String:

println(AnsiEscape { ("hello".red.bold + " world".blue.underline) })
println(AnsiEscape { "hello".color256(33).bgColor256(185) })

Generate a 256 color sequence:

You can generate 256 extra different colors by using color256 and bgColor256:

for (i in 0 until 16) {
    for (j in 0 until 16) {
        val code = i * 16 + j
        print(AnsiEscape { "$code".padStart(4, ' ').color256(code).bgColor256((code + 10) % 256) })
    }
    println()
}
Was this article useful?