Skip to content

milkcocoa0902/colotok

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

97 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

COLOTOK

COLOTOK; Cocoa LogTool for Kotlin

codecov

Feature

âś… 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

Integration

basic dependency

repositories {
    mavenCentral()
    // add this line
    maven(url =  "https://jitpack.io" )
}

dependencies {
    // add this line
    implementation("com.github.milkcocoa0902:colotok:0.1.9")
}

if you use structure logging or create your own provider, you need to add kotlinx-serialization

plugins {
    // add this.
    // set version for your use
    kotlin("plugin.serialization") version "1.9.21"
}

dependencies {
    // add this line to use KSerializer<T> and @Serializable
    implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.0")
}

Usage

Configuration

configure colotok with code.
see below.

val logger = LoggerFactory()
    .addProvider(ConsoleProvider())
    .addProvider(FileProvider(Path.of("./test.log")))
    .getLogger()

more details config

val fileProvider: FileProvider
val logger = LoggerFactory()
    .addProvider(ConsoleProvider{
        // show above info level in console
        level = LogLevel.INFO
    })
    .addProvider(FileProvider(Path.of("./test.log")){
        // write above trace level for file
        level = LogLevel.TRACE
        
        // 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 = 4096)
    }.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")

Print

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"))


// you may need to flash, if log cache is enabled for `FileProvider`
fileProvider.flush()

Formatter(Text)

colotok has builtin text formatter.

  1. PlainTextFormatter
  2. SimpleTextFormatter
  3. DetailTextFormatter

1. PlainFormatter

this formatter shows as below style's log

logger.info("message what happen")

// message what happen

2. SimpleFormatter

this formatter shows as below style's log

logger.info("message what happen")

// 2023-12-29 12:23:14.220383  [INFO] - message what happen

3. DetailFormatter

this 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}

Formatter(Structure)

colotok has builtin structured formatter.

  1. SimpleStructureFormatter
  2. DetailStructureFormatter

if you has a class

@Serializable
class LogDetail(val scope: String, val message: String): LogStructure

@Serializable
class Log(val name: String, val logDetail: LogDetail): LogStructure

1. SimpleStructureFormatter

this formatter shows bellow style's log

logger.info(
    Log(
        name = "illegal state",
        LogDetail(
            "args",
            "argument must be greater than zero"
        )
    ),
    Log.serializer()
)

// // {"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"}

2. DetailStructureFormatter

this formatter shows bellow style's log

logger.info(
    Log(
        name = "illegal state",
        LogDetail(
            "args",
            "argument must be greater than zero"
        )
    ),
    Log.serializer(),
    // 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+09:00"}


logger.info("message what happen")

// {"message":"message what happen","level":"INFO","thread":"main","date":"2023-12-29T12:27:22.5908+09:00"}

Provider

colotok has builtin provider. Provider is used for output log.

  1. ConsoleProvider
  2. FileProvider
  3. StreamProvider

1. ConsoleProvider

this provider outputs log into console with ansi-color

2. FileProvider

this provider output log into file without ansi-color.

3. StreamProvider

this provider output log into stream where you specified.

4. Customize

you can also output to remote or sql or others by create own provider.
example

define custom provider

if you want to write log into slack, you create a SlackProvider like this

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("""
            {"text": "${formatter.format(msg, level, attr)}"}
        """.trimIndent())
                .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("""
            {"text": "${formatter.format(msg, serializer, level, attr)}"}
        """.trimIndent())
                .response()
        }.getOrElse { println(it) }
    }
}

use your provider

now you can use SlackProvider to write the log into slack.

val logger = LoggerFactory()
        .addProvider(ConsoleProvider{
            formatter = DetailTextFormatter
            level = LogLevel.DEBUG
        })
        .addProvider(SlackProvider{
            webhook_url = "your slack webhook url"
            formatter = SimpleTextFormatter
            level = LogLevel.WARN
        })
        .getLogger()

print the log

logger.info("info level log")
// written the log only console

logger.error("error level log")
// written the log both of console and slack

LogLevel

  1. TRACE (all log)
  2. DEBUG (ignore TRACE)
  3. INFO (ignore DEBUG and TRACE)
  4. WARN (only WARN or ERROR)
  5. ERROR (only one)

Document

https://milkcocoa0902.github.io/colotok/01-colotok-introduce.html