Skip to content

Commit

Permalink
Fix slf4j wrapper and log field separator
Browse files Browse the repository at this point in the history
  • Loading branch information
ogesaku committed Feb 11, 2024
1 parent 23e6e70 commit 18012e8
Show file tree
Hide file tree
Showing 9 changed files with 139 additions and 9 deletions.
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/bug-report.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ labels: bug
---

<!-- The bug you're experiencing might have already be reported. -->
<!-- Please search in the [issues](https://github.com/coditory/sherlock-distributed-lock/issues) before creating one. -->
<!-- Please search in the [issues](https://github.com/coditory/klog/issues) before creating one. -->

## Context
<!-- How has this issue affected you? What are you trying to accomplish? -->
Expand Down
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/feature-request.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ about: Suggest new features/changes
labels: feature
---
<!-- Your feature request may already be reported. -->
<!-- Please search in the [issues](https://github.com/coditory/sherlock-distributed-lock/issues) before creating a new one. -->
<!-- Please search in the [issues](https://github.com/coditory/klog/issues) before creating a new one. -->

## Context
<!--- What are you trying to accomplish? -->
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-all.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class Slf4jLoggerWrapper(
override fun trace(
format: String?,
vararg arguments: Any?,
) = logger.trace { MessageFormatter.format(format, arguments).message ?: "" }
) = logger.trace { MessageFormatter.arrayFormat(format, arguments).message ?: "" }

override fun trace(
msg: String?,
Expand Down Expand Up @@ -60,7 +60,7 @@ class Slf4jLoggerWrapper(
override fun debug(
format: String?,
vararg arguments: Any?,
) = logger.debug { MessageFormatter.format(format, arguments).message ?: "" }
) = logger.debug { MessageFormatter.arrayFormat(format, arguments).message ?: "" }

override fun debug(
msg: String?,
Expand Down Expand Up @@ -89,7 +89,7 @@ class Slf4jLoggerWrapper(
override fun info(
format: String?,
vararg arguments: Any?,
) = logger.info { MessageFormatter.format(format, arguments).message ?: "" }
) = logger.info { MessageFormatter.arrayFormat(format, arguments).message ?: "" }

override fun info(
msg: String?,
Expand Down Expand Up @@ -118,7 +118,7 @@ class Slf4jLoggerWrapper(
override fun warn(
format: String?,
vararg arguments: Any?,
) = logger.warn { MessageFormatter.format(format, arguments).message ?: "" }
) = logger.warn { MessageFormatter.arrayFormat(format, arguments).message ?: "" }

override fun warn(
msg: String?,
Expand Down Expand Up @@ -147,7 +147,7 @@ class Slf4jLoggerWrapper(
override fun error(
format: String?,
vararg arguments: Any?,
) = logger.error { MessageFormatter.format(format, arguments).message ?: "" }
) = logger.error { MessageFormatter.arrayFormat(format, arguments).message ?: "" }

override fun error(
msg: String?,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.coditory.klog.publish

import com.coditory.klog.LogEvent
import com.coditory.klog.text.TextLogEventSerializer
import com.coditory.klog.text.plain.PlainTextLogEventSerializer

class InMemoryTextPublisher(
private val serializer: TextLogEventSerializer = PlainTextLogEventSerializer(),
) : BlockingPublisher {
private val logs = mutableListOf<LogEntry>()

@Synchronized
override fun publishBlocking(event: LogEvent) {
val sb = StringBuilder()
serializer.format(event, sb)
logs.add(
LogEntry(
event = event,
message = sb.toString(),
),
)
}

@Synchronized
fun getLogs(): List<String> = logs.map { it.message }

@Synchronized
fun getLastLog(): String? = logs.lastOrNull()?.message

@Synchronized
fun getLogEntries(): List<LogEntry> = logs

@Synchronized
fun getLastLogEntry(): LogEntry? = logs.lastOrNull()

@Synchronized
fun getLogEvents(): List<LogEvent> = logs.map { it.event }

@Synchronized
fun getLastLogEvent(): LogEvent? = logs.lastOrNull()?.event

@Synchronized
fun clear() {
logs.clear()
}

data class LogEntry(
val event: LogEvent,
val message: String,
)

companion object {
const val TEST_THREAD_NAME = "@THREAD"

fun testPublisher(): InMemoryTextPublisher {
return InMemoryTextPublisher(
PlainTextLogEventSerializer(
threadFormatter = { _, appendable -> appendable.append(TEST_THREAD_NAME) },
),
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class PlainTextLogEventSerializer(
if (field == LogEventField.MESSAGE) {
sized.append(messageSeparator)
} else {
sized.append(' ')
sized.appendLazy(' ')
}
length = sized.length()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,27 @@ internal class SizedAppendable(
private val maxLengthMarker: String = MAX_LENGTH_MARKER,
) : Appendable {
private var length: Int = 0
private var lazyAppend: CharSequence? = null
private var lazyAppendChar: Char? = null

fun length(): Int {
return length
}

fun appendLazy(csq: CharSequence): Appendable {
lazyAppend = csq
lazyAppendChar = null
return this
}

fun appendLazy(c: Char): Appendable {
lazyAppend = null
lazyAppendChar = c
return this
}

override fun append(csq: CharSequence?): Appendable {
lazyAppend()
if (length >= maxLength) return this
if (csq != null) {
val csqLength = min(csq.length, maxLength - length)
Expand All @@ -29,6 +44,7 @@ internal class SizedAppendable(
start: Int,
end: Int,
): Appendable {
lazyAppend()
if (length >= maxLength) return this
if (csq != null && start < end) {
val csqLength = min(end - start, maxLength - length)
Expand All @@ -40,6 +56,7 @@ internal class SizedAppendable(
}

override fun append(c: Char): Appendable {
lazyAppend()
if (length >= maxLength) return this
length++
appendable.append(c)
Expand All @@ -53,6 +70,23 @@ internal class SizedAppendable(
}
}

private fun lazyAppend() {
if (length >= maxLength) {
return
}
val lazy = lazyAppend
if (lazy != null) {
lazyAppend = null
append(lazy)
return
}
val lazyChar = lazyAppendChar
if (lazyChar != null) {
lazyAppendChar = null
append(lazyChar)
}
}

companion object {
const val LONG_TEXT_LENGTH: Int = 10 * 1024
const val MAX_LENGTH_MARKER: String = " [trimmed]"
Expand Down
32 changes: 32 additions & 0 deletions klog/src/test/kotlin/com/coditory/klog/KlogComplexPlainTextSpec.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.coditory.klog

import com.coditory.klog.publish.InMemoryTextPublisher
import com.coditory.klog.publish.InMemoryTextPublisher.Companion.TEST_THREAD_NAME
import com.coditory.klog.shared.UpdatableFixedClock
import com.coditory.klog.shared.UpdatableFixedClock.Companion.DEFAULT_FIXED_TIME_LOG_STR
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.shouldBe

class KlogComplexPlainTextSpec : FunSpec({
val clock = UpdatableFixedClock()
val publisher = InMemoryTextPublisher.testPublisher()
val klog =
klog {
clock(clock)
stream {
blockingPublisher(publisher)
}
}

val logger = klog.logger("com.coditory.Logger")

beforeTest {
publisher.clear()
}

test("should emit a basic info log event") {
logger.info { "Hello" }
publisher.getLogs().size shouldBe 1
publisher.getLastLog() shouldBe "$DEFAULT_FIXED_TIME_LOG_STR INFO $TEST_THREAD_NAME com.coditory.Logger: Hello"

Check failure on line 30 in klog/src/test/kotlin/com/coditory/klog/KlogComplexPlainTextSpec.kt

View workflow job for this annotation

GitHub Actions / test report

com.coditory.klog.KlogComplexPlainTextSpec ► should emit a basic info log event

Failed test found in: klog/build/test-results/test/TEST-com.coditory.klog.KlogComplexPlainTextSpec.xml Error: io.kotest.assertions.AssertionFailedError: expected:<"2015-12-03T11:15:30.123456+01:00 INFO @thread com.coditory.Logger: Hello"> but was:<"2015-12-03T10:15:30.123456Z INFO @thread com.coditory.Logger: Hello">
Raw output
io.kotest.assertions.AssertionFailedError: expected:<"2015-12-03T11:15:30.123456+01:00 INFO @THREAD com.coditory.Logger: Hello"> but was:<"2015-12-03T10:15:30.123456Z INFO @THREAD com.coditory.Logger: Hello">
	at app//com.coditory.klog.KlogComplexPlainTextSpec$1$2.invokeSuspend(KlogComplexPlainTextSpec.kt:30)
	at app//com.coditory.klog.KlogComplexPlainTextSpec$1$2.invoke(KlogComplexPlainTextSpec.kt)
	at app//com.coditory.klog.KlogComplexPlainTextSpec$1$2.invoke(KlogComplexPlainTextSpec.kt)
	at app//io.kotest.core.spec.style.scopes.RootScopeKt$addTest$1.invokeSuspend(RootScope.kt:36)
	at app//io.kotest.core.spec.style.scopes.RootScopeKt$addTest$1.invoke(RootScope.kt)
	at app//io.kotest.core.spec.style.scopes.RootScopeKt$addTest$1.invoke(RootScope.kt)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$innerExecute$1.invokeSuspend(TestCaseExecutor.kt:91)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$innerExecute$1.invoke(TestCaseExecutor.kt)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$innerExecute$1.invoke(TestCaseExecutor.kt)
	at app//io.kotest.engine.test.interceptors.CoroutineDebugProbeInterceptor.intercept(CoroutineDebugProbeInterceptor.kt:29)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invokeSuspend(TestCaseExecutor.kt:100)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt)
	at app//io.kotest.engine.test.TestInvocationInterceptor$runBeforeTestAfter$executeWithBeforeAfter$1.invokeSuspend(TestInvocationInterceptor.kt:63)
	at app//io.kotest.engine.test.TestInvocationInterceptor$runBeforeTestAfter$executeWithBeforeAfter$1.invoke(TestInvocationInterceptor.kt)
	at app//io.kotest.engine.test.TestInvocationInterceptor$runBeforeTestAfter$executeWithBeforeAfter$1.invoke(TestInvocationInterceptor.kt)
	at app//io.kotest.engine.test.interceptors.InvocationTimeoutInterceptor$intercept$3.invokeSuspend(InvocationTimeoutInterceptor.kt:43)
	at app//io.kotest.engine.test.interceptors.InvocationTimeoutInterceptor$intercept$3.invoke(InvocationTimeoutInterceptor.kt)
	at app//io.kotest.engine.test.interceptors.InvocationTimeoutInterceptor$intercept$3.invoke(InvocationTimeoutInterceptor.kt)
	at app//kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturnIgnoreTimeout(Undispatched.kt:89)
	at app//kotlinx.coroutines.TimeoutKt.setupTimeout(Timeout.kt:151)
	at app//kotlinx.coroutines.TimeoutKt.withTimeoutOrNull(Timeout.kt:107)
	at app//io.kotest.engine.test.interceptors.InvocationTimeoutInterceptor.intercept(InvocationTimeoutInterceptor.kt:42)
	at app//io.kotest.engine.test.TestInvocationInterceptor$runBeforeTestAfter$wrappedTest$1$1.invokeSuspend(TestInvocationInterceptor.kt:70)
	at app//io.kotest.engine.test.TestInvocationInterceptor$runBeforeTestAfter$wrappedTest$1$1.invoke(TestInvocationInterceptor.kt)
	at app//io.kotest.engine.test.TestInvocationInterceptor$runBeforeTestAfter$wrappedTest$1$1.invoke(TestInvocationInterceptor.kt)
	at app//io.kotest.engine.test.TestInvocationInterceptor.runBeforeTestAfter(TestInvocationInterceptor.kt:73)
	at app//io.kotest.engine.test.TestInvocationInterceptor.access$runBeforeTestAfter(TestInvocationInterceptor.kt:14)
	at app//io.kotest.engine.test.TestInvocationInterceptor$intercept$2$1.invokeSuspend(TestInvocationInterceptor.kt:36)
	at app//io.kotest.engine.test.TestInvocationInterceptor$intercept$2$1.invoke(TestInvocationInterceptor.kt)
	at app//io.kotest.engine.test.TestInvocationInterceptor$intercept$2$1.invoke(TestInvocationInterceptor.kt)
	at app//io.kotest.mpp.ReplayKt.replay(replay.kt:15)
	at app//io.kotest.engine.test.TestInvocationInterceptor$intercept$2.invokeSuspend(TestInvocationInterceptor.kt:32)
	at app//io.kotest.engine.test.TestInvocationInterceptor$intercept$2.invoke(TestInvocationInterceptor.kt)
	at app//io.kotest.engine.test.TestInvocationInterceptor$intercept$2.invoke(TestInvocationInterceptor.kt)
	at app//kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:78)
	at app//kotlinx.coroutines.CoroutineScopeKt.coroutineScope(CoroutineScope.kt:264)
	at app//io.kotest.engine.test.TestInvocationInterceptor.intercept(TestInvocationInterceptor.kt:31)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invokeSuspend(TestCaseExecutor.kt:100)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt)
	at app//io.kotest.engine.interceptors.MarkAbortedExceptionsAsSkippedTestInterceptor.intercept(MarkAbortedExceptionsAsSkippedTestInterceptor.kt:23)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invokeSuspend(TestCaseExecutor.kt:100)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt)
	at app//io.kotest.engine.test.interceptors.ExpectExceptionTestInterceptor.intercept(ExpectExceptionTestInterceptor.kt:18)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invokeSuspend(TestCaseExecutor.kt:100)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt)
	at app//io.kotest.engine.test.interceptors.TimeoutInterceptor.intercept(TimeoutInterceptor.kt:33)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invokeSuspend(TestCaseExecutor.kt:100)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt)
	at app//io.kotest.engine.test.interceptors.BlockedThreadTimeoutInterceptor.intercept(BlockedThreadTimeoutInterceptor.kt:79)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invokeSuspend(TestCaseExecutor.kt:100)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt)
	at app//io.kotest.engine.test.interceptors.CoroutineLoggingInterceptor.intercept(CoroutineLoggingInterceptor.kt:30)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invokeSuspend(TestCaseExecutor.kt:100)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt)
	at app//io.kotest.engine.test.interceptors.SoftAssertInterceptor.intercept(SoftAssertInterceptor.kt:27)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invokeSuspend(TestCaseExecutor.kt:100)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt)
	at app//io.kotest.engine.test.interceptors.AssertionModeInterceptor.intercept(AssertionModeInterceptor.kt:25)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invokeSuspend(TestCaseExecutor.kt:100)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt)
	at app//io.kotest.engine.test.interceptors.LifecycleInterceptor.intercept(LifecycleInterceptor.kt:50)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invokeSuspend(TestCaseExecutor.kt:100)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt)
	at app//io.kotest.engine.test.interceptors.TestCaseExtensionInterceptor$intercept$2.invokeSuspend(TestCaseExtensionInterceptor.kt:24)
	at app//io.kotest.engine.test.interceptors.TestCaseExtensionInterceptor$intercept$2.invoke(TestCaseExtensionInterceptor.kt)
	at app//io.kotest.engine.test.interceptors.TestCaseExtensionInterceptor$intercept$2.invoke(TestCaseExtensionInterceptor.kt)
	at app//io.kotest.engine.test.TestExtensions.intercept(TestExtensions.kt:148)
	at app//io.kotest.engine.test.interceptors.TestCaseExtensionInterceptor.intercept(TestCaseExtensionInterceptor.kt:24)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invokeSuspend(TestCaseExecutor.kt:100)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt)
	at app//io.kotest.engine.test.interceptors.BeforeSpecListenerInterceptor.intercept(BeforeSpecListenerInterceptor.kt:43)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invokeSuspend(TestCaseExecutor.kt:100)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt)
	at app//io.kotest.engine.test.interceptors.TestEnabledCheckInterceptor.intercept(TestEnabledCheckInterceptor.kt:31)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invokeSuspend(TestCaseExecutor.kt:100)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt)
	at app//io.kotest.engine.test.interceptors.CoroutineErrorCollectorInterceptor$intercept$3.invokeSuspend(CoroutineErrorCollectorInterceptor.kt:34)
	at app//io.kotest.engine.test.interceptors.CoroutineErrorCollectorInterceptor$intercept$3.invoke(CoroutineErrorCollectorInterceptor.kt)
	at app//io.kotest.engine.test.interceptors.CoroutineErrorCollectorInterceptor$intercept$3.invoke(CoroutineErrorCollectorInterceptor.kt)
	at app//kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:78)
	at app//kotlinx.coroutines.BuildersKt__Builders_commonKt.withContext(Builders.common.kt:167)
	at app//kotlinx.coroutines.BuildersKt.withContext(Unknown Source)
	at app//io.kotest.engine.test.interceptors.CoroutineErrorCollectorInterceptor.intercept(CoroutineErrorCollectorInterceptor.kt:33)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invokeSuspend(TestCaseExecutor.kt:100)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt)
	at app//io.kotest.engine.test.TestCaseExecutor$execute$3$1.invoke(TestCaseExecutor.kt)
	at app//io.kotest.engine.test.interceptors.CoroutineDispatcherFactoryInterceptor$intercept$4.invokeSuspend(coroutineDispatcherFactoryInterceptor.kt:57)
	at app//io.kotest.engine.test.interceptors.CoroutineDispatcherFactoryInterceptor$intercept$4.invoke(coroutineDispatcherFactoryInterceptor.kt)
	at app//io.kotest.engine.test.interceptors.CoroutineDispatcherFactoryInterceptor$intercept$4.invoke(coroutineDispatcherFactoryInterceptor.kt)
	at app//io.kotest.engine.concurrency.FixedThreadCoroutineDispatcherFactory$withDispatcher$4.invokeSuspend(FixedThreadCoroutineDispatcherFactory.kt:59)
	at app//kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at app//kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108)
	at java.base@21.0.2/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
	at java.base@21.0.2/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
	at java.base@21.0.2/java.lang.Thread.run(Thread.java:1583)
}
})
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class UpdatableFixedClock(

companion object {
// Always use instant with nanos for testing. Some databases (like mongo) trim nanos - you should test for that!
val DEFAULT_FIXED_TIME_LOG_STR = "2015-12-03T11:15:30.123456+01:00"
val DEFAULT_FIXED_TIME = Instant.parse("2015-12-03T10:15:30.123456Z")
val DEFAULT_ZONE_ID = ZoneId.of("Europe/Warsaw")
}
Expand Down

0 comments on commit 18012e8

Please sign in to comment.