log4k: The missing logger for Kotlin Multiplatform...
# multiplatform
y
log4k: The missing logger for Kotlin Multiplatform. This project aims to develop a logger designed for Kotlin Multiplatform that operates asynchronously and is event-driven at its core. Built from the ground up, log4k leverages Kotlin’s coroutines and channels to deliver efficient and scalable logging. https://github.com/smyrgeorge/log4k
l
How does this compare to kermit?
y
The difference is in the architecture and the tracing API that offers. Also it’s a more complete solution (in my opinion), you can hook multiple appenders and each one can process the events/logs in an async manner. for example:
Copy code
// Create custom appenders.
// See [BatchAppender] for more information.
class MyBatchAppender(size: Int) : BatchAppender<LoggingEvent>(size) {
    override suspend fun append(event: List<LoggingEvent>) {
        // E.g. send batch over http.
        // In this case every [append] method will be called every 5 elements.
        println(event.joinToString { it.message })
    }
}

val appender = MyBatchAppender(5)
// Register the appender.
RootLogger.Logging.appenders.register(appender)
Also, keep in mind that the project still is in early stage. For example the tracing API is almost there. I’m also planning to build helpler functionality to store the logging/tracing context in the coroutine scope. Feel free to review the API and suggest any change you think. I also opened a discussion thread for that reason: https://github.com/smyrgeorge/log4k/discussions/2
l
What is the overhead caused by the tracing API?
I'm curious if it can be used in low level performance-sensitive code.
y
I haven’t tested the performance yet. The idea is that all tracing events (also the log events) are enqueued in a Channel. Then they are propagated to each registered appender. An appender can also have a Channel and thus can take control over the underlying Flow. All this works with Kotlin coroutines, with async-io in mind. I think the overhead should be quite low.
l
I'm specifically wondering about the performance when no consumers are set up.
A coroutine function invocation is about twice as slow as a regular call. I had to change my application to remove all the async functions because it was too slow (that said, my use case is a bit special)
Anyway, I'm currently using kermit, but I've been looking for a better solution overall so I'd be interested in testing this.
y
The basic API, that let’s you interact with the logger/tracer does no uses suspend functions. There is only one runBlocking when you send messages to the underlying channel. After that all the processing is happening asynchronously. Try it and let me know. In reality at this point I need input as much as posible. 🙂
l
Thanks. I'll give it a try when I get back from work tonight.
I'll do a test implementation where I migrate the kermit stuff over to your thing.
y
Ok thanks! If something is missing please let me know 🙂
l
It's not on mvnrepository?
y
maybe the mvn repository has not synced yet
I’ll add it to the README
l
Importing it now. Let's see.
💪 1
y
Did you tried it?
l
Looking at it now.
👍 1
This is weird:
Copy code
:test-tools:jsMain: Could not resolve io.github.smyrgeorge:log4k:0.4.0.
Required by:
    project :test-tools > project :array

Possible solution:
 - Declare repository providing the artifact, see the documentation at <https://docs.gradle.org/current/userguide/declaring_repositories.html>
y
I haven’t enabled the build for js yet. In what target you want to build?
During the day I can fix that
l
My project is JS/Linux/JVM/wasmjs at the moment
y
For linux and jvm should work perfectly. For JS i would have to make some small changes first. I’ll try publish the JS version todaty
I just published the version
0.10.0
that also builds for JS and wasmJs. I think there are no braking changes. Try it and let me know 🙂
Did you manage to try it?
l
@Yorgos S. yes, I'm starting to look at it now. My first comment: I believe the log methods should be inline. Otherwise an object is created to wrap the function that returns the message.
I also note that IDEA can't find the source code (usually when following a reference to library code, there is a "download sources" option. This doesn't appear here). I suspect this has to do with how the library was uploaded?
y
You think all the methods should be inline? Or those ones that take a closure? Also, I’ll what’s happening with the sources jar.
l
The ones that take a closure.
Because you want those to be expanded into an inlined
if (should log?) { logger.log(code to get message) }
What happens now is that you will create code like so:
Function fn = new Function() { code to get message }; logger.log(fn)
y
I just published the
0.11.0
version, both of them should be ok now
l
Thanks. The functions are inline now, but I still have two issues: 1) The source is still not there, and 2) It appears only the
error
function accepts a
Throwable
. My code has several cases where I log throwables in debug and info messages.
All message levels should allow throwables.
y
I tested the sources and it was ok, ill test it again. I’ll add the throwable property now. When the new version is ready I’ll let you know
l
Maybe it cached something. I'll clear caches and restart.
Same. Very weird.
y
Just published version
0.12.0
with all the throwable property
Check it, and I’ll check again about the sources
l
OK, works better now.
Let's see if I can get all the testcases to pass
y
🙂
The sources still missing though?
l
Yes, I still don't see them.
All testcases ran fine.
Now I need to write a log handler for this so the UI can display log messages in a separate window.
y
You can register a log appender
l
Right. That's my plan
y
great
what about the performance?
did you notice delays?
l
When running the tool in text mode, I'll collect it to a buffer and provide a command to display any log messages.
I haven't tested that yet.
y
Ok, if you test the performance, please let me know
l
This is the project by the way. The logger is used to monitor internal events in the computation engine. https://codeberg.org/loke/array
y
Coool
starred it 🙂
and also is very cool that you published it on codeberg
I tested the issued with the sources jar in two other projects, and for me works perfectly.
Copy code
Download <https://repo.maven.apache.org/maven2/io/github/smyrgeorge/log4k-macosarm64/0.12.0/log4k-macosarm64-0.12.0.pom>, took 486 ms
Download <https://repo.maven.apache.org/maven2/io/github/smyrgeorge/log4k-macosarm64/0.12.0/log4k-macosarm64-0.12.0.module>, took 199 ms
Download <https://repo.maven.apache.org/maven2/io/github/smyrgeorge/log4k/0.12.0/log4k-0.12.0.jar>, took 161 ms
Download <https://repo.maven.apache.org/maven2/io/github/smyrgeorge/log4k-macosarm64/0.12.0/log4k-macosarm64-0.12.0.klib>, took 161 ms
Download <https://repo.maven.apache.org/maven2/io/github/smyrgeorge/log4k-macosarm64/0.12.0/log4k-macosarm64-0.12.0-sources.jar>, took 144 ms
Download <https://repo.maven.apache.org/maven2/io/github/smyrgeorge/log4k/0.12.0/log4k-0.12.0-sources.jar>, took 23 ms
l
Interesting. Did you test it in an a multiplatform project? I'm asking because that's the only thing I can think of. My project isn't particulary unusual.
I was pretty annoyed with the design of Kermit, so I figured why not actually migrate to yours for a bit. It's pretty low stakes. Here's the commit: https://codeberg.org/loke/array/commit/b828f0a62f5a8e10ad258b5df6a8f3e4ab9bf9a5
y
Yeah I tested in a multi platform project and also in a plain JVM project.
l
Strange
y
Nice! So you plan to keep it? Also, I was thinking to add the logger methods t, d, i, w, e. Lot of people from the android stack would like to see those methods. Also, in the last version I added an appended that protects against log flooding, by dropping events if a certain threshold is exceeded.
l
Possibly. Right now I'm wrapping it in a class that allows me to switch back and forth.
k
My bros helping each other < 3
y
❤️