-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor logging and tracing implementations
Introduce a `TracingEvent` interface and `SimpleConsoleTracingAppender` for tracing support, while refactoring `LoggingEvent` into an interface and renaming ConsoleAppender to `SimpleConsoleLoggingAppender`. This update also includes making the `Appender` interface generic, restructuring `Logger` and `RootLogger` for better logging and tracing separation, and revising tests to incorporate tracing functionality.
- Loading branch information
1 parent
d4f2921
commit afc090b
Showing
17 changed files
with
286 additions
and
97 deletions.
There are no files selected for viewing
4 changes: 2 additions & 2 deletions
4
log4k/src/commonMain/kotlin/io/github/smyrgeorge/log4k/Appender.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
package io.github.smyrgeorge.log4k | ||
|
||
interface Appender { | ||
interface Appender<T> { | ||
val name: String | ||
fun append(event: LoggingEvent) | ||
fun append(event: T) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
67 changes: 49 additions & 18 deletions
67
log4k/src/commonMain/kotlin/io/github/smyrgeorge/log4k/RootLogger.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,50 +1,81 @@ | ||
package io.github.smyrgeorge.log4k | ||
|
||
import io.github.smyrgeorge.log4k.impl.SimpleLoggerFactory | ||
import io.github.smyrgeorge.log4k.impl.appenders.ConsoleAppender | ||
import io.github.smyrgeorge.log4k.impl.appenders.SimpleConsoleLoggingAppender | ||
import io.github.smyrgeorge.log4k.impl.extensions.forEachParallel | ||
import io.github.smyrgeorge.log4k.registry.AppenderRegistry | ||
import io.github.smyrgeorge.log4k.registry.LoggerRegistry | ||
import io.github.smyrgeorge.log4k.impl.registry.AppenderRegistry | ||
import io.github.smyrgeorge.log4k.impl.registry.LoggerRegistry | ||
import kotlinx.coroutines.CoroutineScope | ||
import kotlinx.coroutines.Dispatchers | ||
import kotlinx.coroutines.IO | ||
import kotlinx.coroutines.channels.Channel | ||
import kotlinx.coroutines.channels.consumeEach | ||
import kotlinx.coroutines.launch | ||
import kotlinx.coroutines.runBlocking | ||
import kotlinx.coroutines.sync.Mutex | ||
import kotlinx.coroutines.sync.withLock | ||
import kotlinx.datetime.Clock | ||
import kotlin.coroutines.CoroutineContext | ||
import kotlin.coroutines.EmptyCoroutineContext | ||
|
||
@Suppress("MemberVisibilityCanBePrivate") | ||
object RootLogger { | ||
private val events: Channel<LoggingEvent> = | ||
val level: Level = Level.INFO | ||
|
||
private val logs: Channel<LoggingEvent> = | ||
Channel(capacity = Channel.UNLIMITED) | ||
|
||
val level: Level = Level.INFO | ||
val factory = SimpleLoggerFactory() | ||
val loggers = LoggerRegistry() | ||
val appenders = AppenderRegistry() | ||
private val traces: Channel<TracingEvent> = | ||
Channel(capacity = Channel.UNLIMITED) | ||
|
||
object Logging { | ||
private var idx: Long = 0 | ||
fun id(): Long = ++idx | ||
val factory = SimpleLoggerFactory() | ||
val loggers = LoggerRegistry() | ||
val appenders = AppenderRegistry<LoggingEvent>() | ||
fun register(appender: Appender<LoggingEvent>) = appenders.register(appender) | ||
} | ||
|
||
object Tracing { | ||
private var idx: Long = 0 | ||
var prefix: String = "span" | ||
fun id(): String = runBlocking { "$prefix-${Clock.System.now().epochSeconds}-${idx()}" } | ||
private val mutex = Mutex() | ||
private suspend fun idx(): Long = mutex.withLock { ++idx } | ||
val appenders = AppenderRegistry<TracingEvent>() | ||
fun register(appender: Appender<TracingEvent>) = appenders.register(appender) | ||
} | ||
|
||
init { | ||
register(ConsoleAppender()) | ||
Logging.register(SimpleConsoleLoggingAppender()) | ||
|
||
// Start consuming the logging queue. | ||
// Start consuming the Logging queue. | ||
LoggerScope.launch(Dispatchers.IO) { | ||
events.consumeEach { event -> | ||
event.id = nextIdx() | ||
appenders.all().forEachParallel { it.append(event) } | ||
logs.consumeEach { event -> | ||
event.id = Logging.id() | ||
Logging.appenders.all().forEachParallel { it.append(event) } | ||
} | ||
} | ||
} | ||
|
||
fun log(event: LoggingEvent) = runBlocking { events.send(event) } | ||
fun register(appender: Appender) = appenders.register(appender) | ||
// Start consuming the Tracing queue. | ||
TracerScope.launch(Dispatchers.IO) { | ||
traces.consumeEach { event -> | ||
Tracing.appenders.all().forEachParallel { it.append(event) } | ||
} | ||
} | ||
} | ||
|
||
private var idx: Long = 0 | ||
private fun nextIdx(): Long = ++idx | ||
fun log(event: LoggingEvent) = runBlocking { logs.send(event) } | ||
fun trace(event: TracingEvent) = runBlocking { traces.send(event) } | ||
|
||
private object LoggerScope : CoroutineScope { | ||
override val coroutineContext: CoroutineContext | ||
get() = EmptyCoroutineContext | ||
} | ||
|
||
private object TracerScope : CoroutineScope { | ||
override val coroutineContext: CoroutineContext | ||
get() = EmptyCoroutineContext | ||
} | ||
} |
98 changes: 98 additions & 0 deletions
98
log4k/src/commonMain/kotlin/io/github/smyrgeorge/log4k/TracingEvent.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
package io.github.smyrgeorge.log4k | ||
|
||
import kotlinx.coroutines.runBlocking | ||
import kotlinx.coroutines.sync.Mutex | ||
import kotlinx.coroutines.sync.withLock | ||
import kotlinx.datetime.Clock | ||
import kotlinx.datetime.Instant | ||
|
||
interface TracingEvent { | ||
val id: String | ||
val level: Level | ||
val timestamp: Instant | ||
val tracer: String | ||
val thread: String? | ||
|
||
class Span( | ||
val id: String, | ||
val name: String, | ||
val level: Level, | ||
parent: String? = null, | ||
val logger: Logger, | ||
) { | ||
private val mutex = Mutex() | ||
private var idx: Int = 0 | ||
private var closed: Boolean = false | ||
private fun idx(): Int = ++idx | ||
|
||
init { | ||
val event = Start( | ||
id = id, | ||
name = name, | ||
level = level, | ||
tracer = logger.name, | ||
parent = parent, | ||
) | ||
RootLogger.trace(event) | ||
} | ||
|
||
fun event(msg: String, vararg args: Any?): Unit = withLock { | ||
// If already ended, return. | ||
if (closed) return@withLock | ||
val event = Event( | ||
id = "$id-${idx()}", | ||
spanId = id, | ||
level = level, | ||
tracer = logger.name, | ||
message = msg, | ||
arguments = args, | ||
timestamp = Clock.System.now() | ||
) | ||
RootLogger.trace(event) | ||
} | ||
|
||
fun end(): Unit = withLock { | ||
// If already ended, return. | ||
if (closed) return@withLock | ||
closed = true | ||
|
||
val event = End( | ||
id = id, | ||
level = level, | ||
tracer = logger.name, | ||
) | ||
RootLogger.trace(event) | ||
} | ||
|
||
private fun withLock(f: () -> Unit) = runBlocking { mutex.withLock { f() } } | ||
|
||
class Event( | ||
override val id: String, | ||
val spanId: String, | ||
override val level: Level, | ||
override val tracer: String, | ||
val message: String, | ||
val arguments: Array<out Any?>, | ||
override val timestamp: Instant = Clock.System.now(), | ||
override val thread: String? = null | ||
) : TracingEvent | ||
|
||
class Start( | ||
override var id: String, | ||
val name: String, | ||
override val level: Level, | ||
override val tracer: String, | ||
val parent: String?, | ||
override val timestamp: Instant = Clock.System.now(), | ||
override val thread: String? = null, | ||
) : TracingEvent | ||
|
||
class End( | ||
override var id: String, | ||
override val level: Level, | ||
override val tracer: String, | ||
override val timestamp: Instant = Clock.System.now(), | ||
override val thread: String? = null, | ||
) : TracingEvent | ||
} | ||
} |
5 changes: 2 additions & 3 deletions
5
log4k/src/commonMain/kotlin/io/github/smyrgeorge/log4k/appenders/BatchAppender.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,12 @@ | ||
package io.github.smyrgeorge.log4k.appenders | ||
|
||
import io.github.smyrgeorge.log4k.LoggingEvent | ||
import kotlinx.coroutines.ExperimentalCoroutinesApi | ||
import kotlinx.coroutines.flow.Flow | ||
import kotlinx.coroutines.flow.chunked | ||
|
||
@Suppress("unused") | ||
abstract class BatchAppender(private val size: Int) : FlowAppender<List<LoggingEvent>>() { | ||
abstract class BatchAppender<T>(private val size: Int) : FlowAppender<List<T>, T>() { | ||
@OptIn(ExperimentalCoroutinesApi::class) | ||
override fun setup(flow: Flow<LoggingEvent>): Flow<List<LoggingEvent>> = | ||
override fun setup(flow: Flow<T>): Flow<List<T>> = | ||
flow.chunked(size) | ||
} |
Oops, something went wrong.