commonMain.com.caesarealabs.loggy.lib.InvocationToConsole.kt Maven / Gradle / Ivy
package com.caesarealabs.loggy.lib
import com.caesarealabs.logging.LogSeverity
import com.caesarealabs.loggy.shared.Invocation
import kotlinx.datetime.Instant
import kotlinx.datetime.TimeZone
import kotlinx.datetime.toLocalDateTime
private const val AnsiReset = "\u001B[0m"
private const val AnsiRed = "\u001B[31m"
private const val AnsiGreen = "\u001B[32m"
private const val AnsiYellow = "\u001B[33m"
private const val AnsiGrey = "\u001b[37;1m"
private const val AnsiBold = "\u001b[1m"
private fun String.colored(color: String?) = if(color == null) this else "$color$this$AnsiReset"
private fun String.bold() = "$AnsiBold$this$AnsiReset"
/**
* Will convert this invocation into a string that looks nice when printed to the console.
* Will use colors if [colored] is true.
*/
internal fun Invocation.renderToString(): String {
if (logs.isEmpty() && metadata.isEmpty()) return ""
return buildString {
append("[${startTime.systemDate()} ${startTime.systemTimeOfDay()} -> ${endTime.systemTimeOfDay()}]".colored(AnsiGrey))
append(" $endpoint {\n".bold())
if (metadata.isNotEmpty()) {
append("\t${"Details".bold()} {\n")
for (detail in metadata) {
append("\t\t${detail.key}: ${detail.value.colored(AnsiGreen)}\n")
}
append("\t}\n")
}
if (logs.isNotEmpty()) {
append("\t${"Messages".bold()} {\n")
for (message in logs) {
val color = when (message.severity) {
LogSeverity.Info -> null
LogSeverity.Warn -> AnsiYellow
LogSeverity.Error -> AnsiRed
LogSeverity.Debug -> AnsiGreen
LogSeverity.Verbose -> AnsiGrey
}
append("\t\t")
append("[${message.time.systemTimeOfDay()}]".colored(AnsiGrey))
append(" ${message.severity.name.uppercase()}: ${message.message}\n".colored(color))
}
append("\t}\n")
}
val exceptions = logs.filter { it.exception != null }
if (exceptions.isNotEmpty()) {
append("\t${"Exceptions".bold()} {\n")
for (message in exceptions) {
append("\t\t")
for(element in message.exception!!){
append((element.stacktrace.replace("\n", "\n\t\t") + "\n").colored(AnsiRed))
}
}
append("\t}\n")
}
append("}".bold())
}
}
private val Int.twoCharacters get() = toString().let { if (it.length == 1) "0$it" else it }
private val Int.threeCharacters
get() = toString().let {
"0".repeat(3 - it.length) + it
}
private fun Instant.systemTimeOfDay(): String = with(toLocalDateTime(TimeZone.currentSystemDefault())) {
"${hour.twoCharacters}:${minute.twoCharacters}:${second.twoCharacters}" +
".${(nanosecondsOfSecond / 1_000_000).threeCharacters}"
}
internal fun Instant.systemDate(): String = with(toLocalDateTime(TimeZone.currentSystemDefault())) {
"${dayOfMonth.twoCharacters}/${monthNumber.twoCharacters}/$year"
}