
Enhances logging capabilities with color-coded output, log rotation, and structured logging. Supports custom output locations including console, file, and streams, and allows integration with platforms like Slack.
COLOTOK; Code-Base Logging Runtime for Kotlin
✅ Print log with color
✅ Formatter
✅ Print log where you want
🌟 ConsoleProvider
🌟 FileProvider
🌟 StreamProvider
✅ Log Rotation
🌟 SizeBaseRotation
🌟 DateBaseRotation(; DurationBase)
✅ Customize output location
🌟 example print log into slack
✅ Structure Logging
✅ MDC (Mapped Diagnostic Context)
basic dependency
dependencies {
// add this line
implementation("io.github.milkcocoa0902:colotok:0.3.4")
}or when you use kotlin multiplatform(;KMP)
commonMain.dependncies{
implementation("io.github.milkcocoa0902:colotok:0.3.4")
}
jvmMain.dependencies{
implementation("io.github.milkcocoa0902:colotok-jvm:0.3.4")
}
androidMain.dependencies{
implementation("io.github.milkcocoa0902:colotok-android:0.3.4")
}
jsMain.dependencies{
implementation("io.github.milkcocoa0902:colotok-js:0.3.4")
}Colotok provides several plugins to extend its functionality:
| plugin | artifact | feature | Platform |
|---|---|---|---|
| colotok-coroutines | io.github.milkcocoa0902:colotok-coroutines:0.3.4 |
coroutine support | Multi Platform |
| colotok-slf4j | io.github.milkcocoa0902:colotok-slf4j:0.3.4 |
SLF4J 1.7.x bindings (JVM only) | JVM |
| colotok-slf4j2 | io.github.milkcocoa0902:colotok-slf4j2:0.3.4 |
SLF4J 2.x bindings (JVM only) | JVM |
| colotok-cloudwatch | io.github.milkcocoa0902:colotok-cloudwatch:0.3.4 |
send logs to AWS CloudWatch | JVM |
| colotok-loki | io.github.milkcocoa0902:colotok-loki:0.3.4 |
send logs to Grafana Loki | Multi Platform |
if you use structure logging or create your own provider, you need to add kotlinx.serialization.
when colotok formats into text from your structure, using kotlinx.serialization internally.
plugins {
// add this.
// set version for your use
kotlin("plugin.serialization") version "2.1.10"
}
dependencies {
// add this line to use @Serializable
implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.8.0")
}configure colotok with code.
see below.
val logger = ColotokLoggerContext()
.addProvider(ConsoleProvider())
.getLogger()
more details config
val fileProvider: FileProvider
val logger = ColotokLoggerContext()
.addProvider(ConsoleProvider(ConsoleProviderConfig().apply {
// show above info level in console
level = LogLevel.INFO
}))
.addProvider(FileProvider(File("test.log").toOkioPath()){
level = LogLevel.INFO
// memory buffering to save i/o
enableBuffer = true
// memory buffer size, if buffer excced this, append to file
bufferSize = 2048
// use size base rotation
rotation = SizeBaseRotation(size = 4096L)
}.apply {
fileProvider = this
}).getLogger()
logger.trace("TRACE LEVEL LOG")
logger.debug("DEBUG LEVEL LOG")
logger.info("INFO LEVEL LOG")
logger.warn("WARN LEVEL LOG")
logger.error("ERROR LEVEL LOG")now, you can print log into your space.
logger.trace("TRACE LEVEL LOG")
logger.debug("DEBUG LEVEL LOG")
logger.info("INFO LEVEL LOG")
logger.warn("WARN LEVEL LOG")
logger.error("ERROR LEVEL LOG")
logger.atInfo {
print("in this block")
print("all of logs are printed out with INFO level")
}
// or you can add additional parameters
logger.info("INFO LEVEL LOG", mapOf("param1" to "a custom attr"))colotok has builtin text formatter.
this formatter shows as below style's log
logger.info("message what happen")
// message what happen
this formatter shows as below style's log
logger.info("message what happen")
// 2023-12-29 12:23:14.220383 [INFO] - message what happenthis formatter shows as below style's log
logger.ingo("message what happen", mapOf("param1" to "a custom attribute"))
// 2023-12-29T12:21:13.354328+09:00 (main)[INFO] - message what happen, additional = {param1=a custom attribute}colotok has builtin structured formatter.
if you has a class
@Serializable
class LogDetail(val scope: String, val message: String): LogStructure
@Serializable
class Log(val name: String, val logDetail: LogDetail): LogStructurethis formatter shows bellow style's log
logger.info(
Log(
name = "illegal state",
LogDetail(
"args",
"argument must be greater than zero"
)
)
)
// // {"message":{"name":"illegal state","logDetail":{"scope":"args","message":"argument must be greater than zero"}},"level":"INFO","date":"2023-12-29"}
logger.info("message what happen")
// {"msg":"message what happen","level":"INFO","date":"2023-12-29"}this formatter shows bellow style's log
logger.info(
Log(
name = "illegal state",
LogDetail(
"args",
"argument must be greater than zero"
)
),
// you can pass additional attrs
mapOf("additional" to "additional param")
)
// {"message":{"name":"illegal state","logDetail":{"scope":"args","message":"argument must be greater than zero"}},"level":"INFO","additional":"additional param","date":"2023-12-29T12:34:56"}
logger.info("message what happen")
// {"message":"message what happen","level":"INFO","thread":"main","date":"2023-12-29T12:27:22.5908"}colotok has builtin provider. Provider is used for output log.
this provider outputs log into console with ansi-color
this provider output log into file without ansi-color.
this provider output log into stream where you specified.
you can also output to remote or sql or others by create own provider.
example
if you want to write log into slack, you create a SlackProvider like this
@Serializable
data class SlackWebhookPayload(
val text: String,
)
class SlackProvider(config: SlackProviderConfig): Provider {
constructor(config: SlackProviderConfig.() -> Unit): this(SlackProviderConfig().apply(config))
class SlackProviderConfig() : ProviderConfig {
var webhook_url: String = ""
override var level: level = LogLevel.DEBUG
override var formatter: Formatter = DetailTextFormatter
}
private val webhookUrl = config.webhook_url
private val logLevel = config.level
private val formatter = config.formatter
override fun write(name: String, msg: String, level: LogLevel, attr: Map<String, String>) {
if(level.isEnabledFor(logLevel).not()){
return
}
kotlin.runCatching {
webhookUrl.httpPost()
.appendHeader("Content-Type" to "application/json")
.body(Json.encodeToString(text = formatter.format(msg, level, attr)))
.response()
}.getOrElse { println(it) }
}
override fun <T : LogStructure> write(
name: String,
msg: T,
serializer: KSerializer<T>,
level: LogLevel,
attr: Map<String, String>
) {
if(level.isEnabledFor(logLevel).not()){
return
}
kotlin.runCatching {
webhookUrl.httpPost()
.appendHeader("Content-Type" to "application/json")
.body(Json.encodeToString(text = formatter.format(msg, serializer, level, attr)))
.response()
}.getOrElse { println(it) }
}
}now you can use SlackProvider to write the log into slack.
val logger = ColotokLoggerContext()
.addProvider(ConsoleProvider(ConsoleProviderConfig().apply {
formatter = DetailTextFormatter
level = LogLevel.DEBUG
}))
.addProvider(SlackProvider{
webhook_url = "your slack webhook url"
formatter = SimpleTextFormatter
level = LogLevel.WARN
})
.getLogger()logger.info("info level log")
// written the log only console
logger.error("error level log")
// written the log both of console and slackColotok supports MDC functionality since version 0.3.0, which allows you to add contextual information to your logs. MDC is designed to be coroutine-friendly.
MDC replace the Element.CUSTOM when formatting.
// Set MDC values
MDC.put("requestId", "12345")
MDC.put("userId", "user-abc")
// Log with MDC context
logger.info("Processing request") // MDC values will be included automatically
// Clear specific MDC value
MDC.remove("userId")
// Clear all MDC values
MDC.clear()
// Using MDC with coroutines
// On JVM platform
suspend fun processRequest() {
withMdcScope(Dispatchers.IO) {
MDC.put("requestId", "12345")
// MDC context is preserved across coroutine boundaries
someAsyncOperation()
}
}
// On JS platform
fun processRequest() {
MDC.withContext {
MDC.put("requestId", "12345")
// MDC context is preserved within this block
someOperation()
}
}
// Alternative syntax on JS
fun processRequest() {
withMdcScope {
MDC.put("requestId", "12345")
// MDC context is preserved within this block
someOperation()
}
}https://milkcocoa0902.github.io/colotok/01-colotok-introduce.html
COLOTOK; Code-Base Logging Runtime for Kotlin
✅ Print log with color
✅ Formatter
✅ Print log where you want
🌟 ConsoleProvider
🌟 FileProvider
🌟 StreamProvider
✅ Log Rotation
🌟 SizeBaseRotation
🌟 DateBaseRotation(; DurationBase)
✅ Customize output location
🌟 example print log into slack
✅ Structure Logging
✅ MDC (Mapped Diagnostic Context)
basic dependency
dependencies {
// add this line
implementation("io.github.milkcocoa0902:colotok:0.3.4")
}or when you use kotlin multiplatform(;KMP)
commonMain.dependncies{
implementation("io.github.milkcocoa0902:colotok:0.3.4")
}
jvmMain.dependencies{
implementation("io.github.milkcocoa0902:colotok-jvm:0.3.4")
}
androidMain.dependencies{
implementation("io.github.milkcocoa0902:colotok-android:0.3.4")
}
jsMain.dependencies{
implementation("io.github.milkcocoa0902:colotok-js:0.3.4")
}Colotok provides several plugins to extend its functionality:
| plugin | artifact | feature | Platform |
|---|---|---|---|
| colotok-coroutines | io.github.milkcocoa0902:colotok-coroutines:0.3.4 |
coroutine support | Multi Platform |
| colotok-slf4j | io.github.milkcocoa0902:colotok-slf4j:0.3.4 |
SLF4J 1.7.x bindings (JVM only) | JVM |
| colotok-slf4j2 | io.github.milkcocoa0902:colotok-slf4j2:0.3.4 |
SLF4J 2.x bindings (JVM only) | JVM |
| colotok-cloudwatch | io.github.milkcocoa0902:colotok-cloudwatch:0.3.4 |
send logs to AWS CloudWatch | JVM |
| colotok-loki | io.github.milkcocoa0902:colotok-loki:0.3.4 |
send logs to Grafana Loki | Multi Platform |
if you use structure logging or create your own provider, you need to add kotlinx.serialization.
when colotok formats into text from your structure, using kotlinx.serialization internally.
plugins {
// add this.
// set version for your use
kotlin("plugin.serialization") version "2.1.10"
}
dependencies {
// add this line to use @Serializable
implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.8.0")
}configure colotok with code.
see below.
val logger = ColotokLoggerContext()
.addProvider(ConsoleProvider())
.getLogger()
more details config
val fileProvider: FileProvider
val logger = ColotokLoggerContext()
.addProvider(ConsoleProvider(ConsoleProviderConfig().apply {
// show above info level in console
level = LogLevel.INFO
}))
.addProvider(FileProvider(File("test.log").toOkioPath()){
level = LogLevel.INFO
// memory buffering to save i/o
enableBuffer = true
// memory buffer size, if buffer excced this, append to file
bufferSize = 2048
// use size base rotation
rotation = SizeBaseRotation(size = 4096L)
}.apply {
fileProvider = this
}).getLogger()
logger.trace("TRACE LEVEL LOG")
logger.debug("DEBUG LEVEL LOG")
logger.info("INFO LEVEL LOG")
logger.warn("WARN LEVEL LOG")
logger.error("ERROR LEVEL LOG")now, you can print log into your space.
logger.trace("TRACE LEVEL LOG")
logger.debug("DEBUG LEVEL LOG")
logger.info("INFO LEVEL LOG")
logger.warn("WARN LEVEL LOG")
logger.error("ERROR LEVEL LOG")
logger.atInfo {
print("in this block")
print("all of logs are printed out with INFO level")
}
// or you can add additional parameters
logger.info("INFO LEVEL LOG", mapOf("param1" to "a custom attr"))colotok has builtin text formatter.
this formatter shows as below style's log
logger.info("message what happen")
// message what happen
this formatter shows as below style's log
logger.info("message what happen")
// 2023-12-29 12:23:14.220383 [INFO] - message what happenthis formatter shows as below style's log
logger.ingo("message what happen", mapOf("param1" to "a custom attribute"))
// 2023-12-29T12:21:13.354328+09:00 (main)[INFO] - message what happen, additional = {param1=a custom attribute}colotok has builtin structured formatter.
if you has a class
@Serializable
class LogDetail(val scope: String, val message: String): LogStructure
@Serializable
class Log(val name: String, val logDetail: LogDetail): LogStructurethis formatter shows bellow style's log
logger.info(
Log(
name = "illegal state",
LogDetail(
"args",
"argument must be greater than zero"
)
)
)
// // {"message":{"name":"illegal state","logDetail":{"scope":"args","message":"argument must be greater than zero"}},"level":"INFO","date":"2023-12-29"}
logger.info("message what happen")
// {"msg":"message what happen","level":"INFO","date":"2023-12-29"}this formatter shows bellow style's log
logger.info(
Log(
name = "illegal state",
LogDetail(
"args",
"argument must be greater than zero"
)
),
// you can pass additional attrs
mapOf("additional" to "additional param")
)
// {"message":{"name":"illegal state","logDetail":{"scope":"args","message":"argument must be greater than zero"}},"level":"INFO","additional":"additional param","date":"2023-12-29T12:34:56"}
logger.info("message what happen")
// {"message":"message what happen","level":"INFO","thread":"main","date":"2023-12-29T12:27:22.5908"}colotok has builtin provider. Provider is used for output log.
this provider outputs log into console with ansi-color
this provider output log into file without ansi-color.
this provider output log into stream where you specified.
you can also output to remote or sql or others by create own provider.
example
if you want to write log into slack, you create a SlackProvider like this
@Serializable
data class SlackWebhookPayload(
val text: String,
)
class SlackProvider(config: SlackProviderConfig): Provider {
constructor(config: SlackProviderConfig.() -> Unit): this(SlackProviderConfig().apply(config))
class SlackProviderConfig() : ProviderConfig {
var webhook_url: String = ""
override var level: level = LogLevel.DEBUG
override var formatter: Formatter = DetailTextFormatter
}
private val webhookUrl = config.webhook_url
private val logLevel = config.level
private val formatter = config.formatter
override fun write(name: String, msg: String, level: LogLevel, attr: Map<String, String>) {
if(level.isEnabledFor(logLevel).not()){
return
}
kotlin.runCatching {
webhookUrl.httpPost()
.appendHeader("Content-Type" to "application/json")
.body(Json.encodeToString(text = formatter.format(msg, level, attr)))
.response()
}.getOrElse { println(it) }
}
override fun <T : LogStructure> write(
name: String,
msg: T,
serializer: KSerializer<T>,
level: LogLevel,
attr: Map<String, String>
) {
if(level.isEnabledFor(logLevel).not()){
return
}
kotlin.runCatching {
webhookUrl.httpPost()
.appendHeader("Content-Type" to "application/json")
.body(Json.encodeToString(text = formatter.format(msg, serializer, level, attr)))
.response()
}.getOrElse { println(it) }
}
}now you can use SlackProvider to write the log into slack.
val logger = ColotokLoggerContext()
.addProvider(ConsoleProvider(ConsoleProviderConfig().apply {
formatter = DetailTextFormatter
level = LogLevel.DEBUG
}))
.addProvider(SlackProvider{
webhook_url = "your slack webhook url"
formatter = SimpleTextFormatter
level = LogLevel.WARN
})
.getLogger()logger.info("info level log")
// written the log only console
logger.error("error level log")
// written the log both of console and slackColotok supports MDC functionality since version 0.3.0, which allows you to add contextual information to your logs. MDC is designed to be coroutine-friendly.
MDC replace the Element.CUSTOM when formatting.
// Set MDC values
MDC.put("requestId", "12345")
MDC.put("userId", "user-abc")
// Log with MDC context
logger.info("Processing request") // MDC values will be included automatically
// Clear specific MDC value
MDC.remove("userId")
// Clear all MDC values
MDC.clear()
// Using MDC with coroutines
// On JVM platform
suspend fun processRequest() {
withMdcScope(Dispatchers.IO) {
MDC.put("requestId", "12345")
// MDC context is preserved across coroutine boundaries
someAsyncOperation()
}
}
// On JS platform
fun processRequest() {
MDC.withContext {
MDC.put("requestId", "12345")
// MDC context is preserved within this block
someOperation()
}
}
// Alternative syntax on JS
fun processRequest() {
withMdcScope {
MDC.put("requestId", "12345")
// MDC context is preserved within this block
someOperation()
}
}https://milkcocoa0902.github.io/colotok/01-colotok-introduce.html