Skip to content

Commit f65747b

Browse files
committed
better logging support & asyncBouncer enchanced
1 parent 4babd35 commit f65747b

5 files changed

Lines changed: 66 additions & 15 deletions

File tree

build.gradle.kts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ plugins {
77
}
88

99
group = "net.sergeych"
10-
version = "1.2.0"
10+
version = "1.2.2-SNAPSHOT"
11+
1112
val serialization_version = "1.3.2"
1213

1314
repositories {
@@ -50,14 +51,14 @@ kotlin {
5051
val commonMain by getting {
5152
dependencies {
5253
api("org.jetbrains.kotlinx:kotlinx-serialization-json:$serialization_version")
53-
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0")
54+
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.1")
5455
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.3.2")
5556
}
5657
}
5758
val commonTest by getting {
5859
dependencies {
5960
implementation(kotlin("test"))
60-
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.0")
61+
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.1")
6162
}
6263
}
6364
val jvmMain by getting

src/commonMain/kotlin/net/sergeych/mp_logger/Loggable.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import kotlinx.coroutines.flow.MutableSharedFlow
99
import kotlinx.coroutines.flow.asSharedFlow
1010
import kotlinx.datetime.Clock
1111
import kotlinx.datetime.Instant
12+
import kotlinx.serialization.SerialName
1213
import kotlinx.serialization.Serializable
1314
import net.sergeych.mp_logger.Log.connectConsole
1415
import net.sergeych.mp_logger.Log.logFlow
@@ -143,13 +144,17 @@ sealed class LogData {
143144
/**
144145
* The regular log message: no additional data
145146
*/
147+
@Serializable
148+
@SerialName("msg")
146149
class Message(override val tag: String, override val message: String) : LogData() {
147150
override fun toString(): String = message
148151
}
149152

150153
/**
151154
* Error log message: also an optional stack.
152155
*/
156+
@Serializable
157+
@SerialName("err")
153158
class Error(
154159
override val tag: String,
155160
override val message: String,

src/commonMain/kotlin/net/sergeych/mp_tools/AsyncBouncer.kt

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,59 @@ import kotlin.time.Duration
1414
/**
1515
* Expermiental multiplatform coroutine-based bouncer: safe way to call some suspend code
1616
* after a timeout. It is thread-safe (where multithreaded) and coroutine-safe.
17+
*
18+
* Note that creating a bouncer will not invoke its callback until the corresponding pulse call.
19+
*
20+
* @param initialTimeout default timeout for [pulse], could be changed at runtime assigning to [timeout].
21+
* @param initialMaxTimeout maximum timeout between calls, systemm will invoke callback when it expires even if there
22+
* will be [pulse] calls in between. Could be changed with [maxTimeout]
23+
* @param callback what to invoke.
1724
*/
18-
class AsyncBouncer(var timeout: Duration, callback: suspend () -> Unit) {
25+
class AsyncBouncer(
26+
initialTimeout: Duration,
27+
initialMaxTimeout: Duration = initialTimeout,
28+
callback: suspend () -> Unit,
29+
) {
1930

31+
private var lastCallAt: Instant? = null
2032
private var callAt: Instant? = null
2133
private val access = Mutex()
2234
private val pulseChannel = Channel<Int>(0, onBufferOverflow = BufferOverflow.DROP_OLDEST)
2335

36+
/**
37+
* Default time between call to [pulse] and invocation. Assigning calls [pulse].
38+
*/
39+
var timeout: Duration = initialTimeout
40+
set(value) {
41+
field = value
42+
pulse()
43+
}
44+
45+
/**
46+
* Maximim time between invocations: even if [pulse] is being called more often, invocations will happen at this
47+
* rate. Assigning it calls [pulse]
48+
*/
49+
var maxTimeout: Duration = initialMaxTimeout
50+
set(value) {
51+
field = value
52+
pulse()
53+
}
54+
2455
/**
2556
* Cause a block to be scheduled after [timeout] or right now from now even it is already being executing.
57+
* To change effective [timeout], assign a value to it _prior to call pulse_.
2658
*/
27-
suspend fun pulse(now: Boolean = false) {
28-
access.withReentrantLock {
29-
checkNotClosed()
30-
callAt = if (now) Now() else Now() + timeout
31-
pulseChannel.send(1)
59+
fun pulse(now: Boolean = false) {
60+
checkNotClosed()
61+
globalLaunch {
62+
access.withReentrantLock {
63+
callAt = if (now) Now() else Now() + timeout
64+
lastCallAt?.let {
65+
val limitTime = it + maxTimeout
66+
if (callAt!! > limitTime) callAt = limitTime
67+
}
68+
pulseChannel.send(1)
69+
}
3270
}
3371
}
3472

@@ -89,8 +127,8 @@ class AsyncBouncer(var timeout: Duration, callback: suspend () -> Unit) {
89127
try {
90128
callback()
91129
callAt = null
92-
}
93-
catch(t: Throwable) {
130+
lastCallAt = Now()
131+
} catch (t: Throwable) {
94132
// we can't use logging here as logger uses us ;)
95133
println("unexpected error in AsyncBouncer: $t")
96134
t.printStackTrace()

src/jvmMain/kotlin/net/sergeych/mp_logger/FileLogCatcher.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,9 @@ class FileLogCatcher(name: String, level: Log.Level = Log.Level.DEBUG, rotate: B
102102

103103
println("writing to $currentLog")
104104

105-
bouncer = AsyncBouncer(100.milliseconds) { withContext(Dispatchers.IO) { out.flush() } }
105+
bouncer = AsyncBouncer(100.milliseconds, 100.milliseconds) { withContext(Dispatchers.IO) {
106+
out.flush()
107+
} }
106108

107109
job = globalLaunch {
108110
Log.logFlow.collect {

src/jvmTest/kotlin/mo_logger/TestLogger.kt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,15 @@ class TestLogger {
5656
// println("test bouncer")
5757
// }
5858
// b.pulse(true)
59-
val c = FileLogCatcher("testlog", rotate = true)
59+
val c = FileLogCatcher("testlog",rotate = true)
6060
val x = LogTag("TFILE")
61-
x.info { "--------- we run ------------" }
62-
c.flush()
61+
delay(300)
62+
for(i in 1..20) {
63+
x.info { "--------- we run ------------" }
64+
delay(50)
65+
}
66+
delay(4000)
67+
6368
}
6469
}
6570

0 commit comments

Comments
 (0)