From 990c754331d3e368296a5b99529f1be21326d012 Mon Sep 17 00:00:00 2001 From: Cedrick Cooke Date: Tue, 13 Apr 2021 16:59:47 -0700 Subject: [PATCH 1/3] Add metadata --- logging/api/logging.api | 72 +++++++++++-------- .../src/commonMain/kotlin/DispatchLogger.kt | 24 +++---- logging/src/commonMain/kotlin/Key.kt | 7 ++ logging/src/commonMain/kotlin/Log.kt | 47 ++++++++---- logging/src/commonMain/kotlin/Logger.kt | 24 +++---- logging/src/commonMain/kotlin/Metadata.kt | 42 +++++++++++ logging/src/commonMain/kotlin/Pool.kt | 16 +++++ logging/src/commonTest/kotlin/Call.kt | 3 +- .../src/commonTest/kotlin/CallListLogger.kt | 24 +++---- .../commonTest/kotlin/DispatchLoggerTests.kt | 35 +++++---- .../src/commonTest/kotlin/MetadataTests.kt | 48 +++++++++++++ logging/src/jsMain/kotlin/ConsoleLogger.kt | 12 ++-- logging/src/jvmMain/kotlin/ConsoleLogger.kt | 12 ++-- .../src/jvmTest/kotlin/ConsoleLoggerTests.kt | 24 +++---- .../src/macosX64Main/kotlin/ConsoleLogger.kt | 12 ++-- 15 files changed, 279 insertions(+), 123 deletions(-) create mode 100644 logging/src/commonMain/kotlin/Key.kt create mode 100644 logging/src/commonMain/kotlin/Metadata.kt create mode 100644 logging/src/commonMain/kotlin/Pool.kt create mode 100644 logging/src/commonTest/kotlin/MetadataTests.kt diff --git a/logging/api/logging.api b/logging/api/logging.api index 52152341..e1b64deb 100644 --- a/logging/api/logging.api +++ b/logging/api/logging.api @@ -1,11 +1,11 @@ public final class com/juul/tuulbox/logging/ConsoleLogger : com/juul/tuulbox/logging/Logger { public static final field INSTANCE Lcom/juul/tuulbox/logging/ConsoleLogger; - public fun assert (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)V - public fun debug (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)V - public fun error (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)V - public fun info (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)V - public fun verbose (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)V - public fun warn (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)V + public fun assert (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Lcom/juul/tuulbox/logging/ReadMetadata;)V + public fun debug (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Lcom/juul/tuulbox/logging/ReadMetadata;)V + public fun error (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Lcom/juul/tuulbox/logging/ReadMetadata;)V + public fun info (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Lcom/juul/tuulbox/logging/ReadMetadata;)V + public fun verbose (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Lcom/juul/tuulbox/logging/ReadMetadata;)V + public fun warn (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Lcom/juul/tuulbox/logging/ReadMetadata;)V } public final class com/juul/tuulbox/logging/ConstantTagGenerator : com/juul/tuulbox/logging/TagGenerator { @@ -15,45 +15,57 @@ public final class com/juul/tuulbox/logging/ConstantTagGenerator : com/juul/tuul public final class com/juul/tuulbox/logging/DispatchLogger : com/juul/tuulbox/logging/Logger { public fun ()V - public fun assert (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)V + public fun assert (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Lcom/juul/tuulbox/logging/ReadMetadata;)V public final fun clear ()V - public fun debug (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)V - public fun error (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)V - public fun info (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)V + public fun debug (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Lcom/juul/tuulbox/logging/ReadMetadata;)V + public fun error (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Lcom/juul/tuulbox/logging/ReadMetadata;)V + public fun info (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Lcom/juul/tuulbox/logging/ReadMetadata;)V public final fun install (Lcom/juul/tuulbox/logging/Logger;)V - public fun verbose (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)V - public fun warn (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)V + public fun verbose (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Lcom/juul/tuulbox/logging/ReadMetadata;)V + public fun warn (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Lcom/juul/tuulbox/logging/ReadMetadata;)V +} + +public abstract interface class com/juul/tuulbox/logging/Key { } public final class com/juul/tuulbox/logging/Log { public static final field INSTANCE Lcom/juul/tuulbox/logging/Log; - public final fun assert (Ljava/lang/Throwable;Ljava/lang/String;Lkotlin/jvm/functions/Function0;)V - public static synthetic fun assert$default (Lcom/juul/tuulbox/logging/Log;Ljava/lang/Throwable;Ljava/lang/String;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)V - public final fun debug (Ljava/lang/Throwable;Ljava/lang/String;Lkotlin/jvm/functions/Function0;)V - public static synthetic fun debug$default (Lcom/juul/tuulbox/logging/Log;Ljava/lang/Throwable;Ljava/lang/String;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)V - public final fun error (Ljava/lang/Throwable;Ljava/lang/String;Lkotlin/jvm/functions/Function0;)V - public static synthetic fun error$default (Lcom/juul/tuulbox/logging/Log;Ljava/lang/Throwable;Ljava/lang/String;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)V + public final fun assert (Ljava/lang/Throwable;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V + public static synthetic fun assert$default (Lcom/juul/tuulbox/logging/Log;Ljava/lang/Throwable;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V + public final fun debug (Ljava/lang/Throwable;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V + public static synthetic fun debug$default (Lcom/juul/tuulbox/logging/Log;Ljava/lang/Throwable;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V + public final fun error (Ljava/lang/Throwable;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V + public static synthetic fun error$default (Lcom/juul/tuulbox/logging/Log;Ljava/lang/Throwable;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V public final fun getDispatcher ()Lcom/juul/tuulbox/logging/DispatchLogger; public final fun getTagGenerator ()Lcom/juul/tuulbox/logging/TagGenerator; - public final fun info (Ljava/lang/Throwable;Ljava/lang/String;Lkotlin/jvm/functions/Function0;)V - public static synthetic fun info$default (Lcom/juul/tuulbox/logging/Log;Ljava/lang/Throwable;Ljava/lang/String;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)V + public final fun info (Ljava/lang/Throwable;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V + public static synthetic fun info$default (Lcom/juul/tuulbox/logging/Log;Ljava/lang/Throwable;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V public final fun setTagGenerator (Lcom/juul/tuulbox/logging/TagGenerator;)V - public final fun verbose (Ljava/lang/Throwable;Ljava/lang/String;Lkotlin/jvm/functions/Function0;)V - public static synthetic fun verbose$default (Lcom/juul/tuulbox/logging/Log;Ljava/lang/Throwable;Ljava/lang/String;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)V - public final fun warn (Ljava/lang/Throwable;Ljava/lang/String;Lkotlin/jvm/functions/Function0;)V - public static synthetic fun warn$default (Lcom/juul/tuulbox/logging/Log;Ljava/lang/Throwable;Ljava/lang/String;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)V + public final fun verbose (Ljava/lang/Throwable;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V + public static synthetic fun verbose$default (Lcom/juul/tuulbox/logging/Log;Ljava/lang/Throwable;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V + public final fun warn (Ljava/lang/Throwable;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V + public static synthetic fun warn$default (Lcom/juul/tuulbox/logging/Log;Ljava/lang/Throwable;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V } public abstract interface class com/juul/tuulbox/logging/Logger { - public abstract fun assert (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)V - public abstract fun debug (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)V - public abstract fun error (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)V - public abstract fun info (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)V - public abstract fun verbose (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)V - public abstract fun warn (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)V + public abstract fun assert (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Lcom/juul/tuulbox/logging/ReadMetadata;)V + public abstract fun debug (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Lcom/juul/tuulbox/logging/ReadMetadata;)V + public abstract fun error (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Lcom/juul/tuulbox/logging/ReadMetadata;)V + public abstract fun info (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Lcom/juul/tuulbox/logging/ReadMetadata;)V + public abstract fun verbose (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Lcom/juul/tuulbox/logging/ReadMetadata;)V + public abstract fun warn (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Lcom/juul/tuulbox/logging/ReadMetadata;)V +} + +public abstract interface class com/juul/tuulbox/logging/ReadMetadata { + public abstract fun copy ()Lcom/juul/tuulbox/logging/ReadMetadata; + public abstract fun get (Lcom/juul/tuulbox/logging/Key;)Ljava/lang/Object; } public abstract interface class com/juul/tuulbox/logging/TagGenerator { public abstract fun getTag ()Ljava/lang/String; } +public abstract interface class com/juul/tuulbox/logging/WriteMetadata { + public abstract fun set (Lcom/juul/tuulbox/logging/Key;Ljava/lang/Object;)V +} + diff --git a/logging/src/commonMain/kotlin/DispatchLogger.kt b/logging/src/commonMain/kotlin/DispatchLogger.kt index 88c35b09..573571a5 100644 --- a/logging/src/commonMain/kotlin/DispatchLogger.kt +++ b/logging/src/commonMain/kotlin/DispatchLogger.kt @@ -21,27 +21,27 @@ public class DispatchLogger : Logger { consumers.value = emptySet() } - override fun verbose(tag: String, message: String, throwable: Throwable?) { - consumers.value.forEach { it.verbose(tag, message, throwable) } + override fun verbose(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { + consumers.value.forEach { it.verbose(tag, message, throwable, metadata) } } - override fun debug(tag: String, message: String, throwable: Throwable?) { - consumers.value.forEach { it.debug(tag, message, throwable) } + override fun debug(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { + consumers.value.forEach { it.debug(tag, message, throwable, metadata) } } - override fun info(tag: String, message: String, throwable: Throwable?) { - consumers.value.forEach { it.info(tag, message, throwable) } + override fun info(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { + consumers.value.forEach { it.info(tag, message, throwable, metadata) } } - override fun warn(tag: String, message: String, throwable: Throwable?) { - consumers.value.forEach { it.warn(tag, message, throwable) } + override fun warn(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { + consumers.value.forEach { it.warn(tag, message, throwable, metadata) } } - override fun error(tag: String, message: String, throwable: Throwable?) { - consumers.value.forEach { it.error(tag, message, throwable) } + override fun error(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { + consumers.value.forEach { it.error(tag, message, throwable, metadata) } } - override fun assert(tag: String, message: String, throwable: Throwable?) { - consumers.value.forEach { it.assert(tag, message, throwable) } + override fun assert(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { + consumers.value.forEach { it.assert(tag, message, throwable, metadata) } } } diff --git a/logging/src/commonMain/kotlin/Key.kt b/logging/src/commonMain/kotlin/Key.kt new file mode 100644 index 00000000..c2395a24 --- /dev/null +++ b/logging/src/commonMain/kotlin/Key.kt @@ -0,0 +1,7 @@ +package com.juul.tuulbox.logging + +/** + * Marker interface to strongly type metadata with its key. Proper usage is + * to create `object`s or `enum class`es when implementing this type. + */ +public interface Key diff --git a/logging/src/commonMain/kotlin/Log.kt b/logging/src/commonMain/kotlin/Log.kt index 7a06d0ba..6e915345 100644 --- a/logging/src/commonMain/kotlin/Log.kt +++ b/logging/src/commonMain/kotlin/Log.kt @@ -1,6 +1,11 @@ package com.juul.tuulbox.logging +import com.juul.tuulbox.logging.Log.dispatcher import kotlinx.atomicfu.atomic +import kotlin.native.concurrent.ThreadLocal + +@ThreadLocal // Pool mutates internal state, easiest solution is to thread-local this in Kotlin/Native. +private val metadataPool = Pool(factory = ::Metadata, refurbish = Metadata::clear) /** Global logging object. To receive logs, call [dispatcher].[install][DispatchLogger.install]. */ public object Log { @@ -18,44 +23,62 @@ public object Log { } /** Send a verbose-level log message to the global dispatcher. */ - public fun verbose(throwable: Throwable? = null, tag: String? = null, message: () -> String) { + public fun verbose(throwable: Throwable? = null, tag: String? = null, message: (WriteMetadata) -> String) { if (dispatcher.hasConsumers) { - dispatcher.verbose(tag ?: tagGenerator.getTag(), message.invoke(), throwable) + val metadata = metadataPool.borrow() + val body = message(metadata) + dispatcher.verbose(tag ?: tagGenerator.getTag(), body, throwable, metadata) + metadataPool.recycle(metadata) } } /** Send a debug-level log message to the global dispatcher. */ - public fun debug(throwable: Throwable? = null, tag: String? = null, message: () -> String) { + public fun debug(throwable: Throwable? = null, tag: String? = null, message: (WriteMetadata) -> String) { if (dispatcher.hasConsumers) { - dispatcher.debug(tag ?: tagGenerator.getTag(), message.invoke(), throwable) + val metadata = metadataPool.borrow() + val body = message(metadata) + dispatcher.debug(tag ?: tagGenerator.getTag(), body, throwable, metadata) + metadataPool.recycle(metadata) } } /** Send an info-level log message to the global dispatcher. */ - public fun info(throwable: Throwable? = null, tag: String? = null, message: () -> String) { + public fun info(throwable: Throwable? = null, tag: String? = null, message: (WriteMetadata) -> String) { if (dispatcher.hasConsumers) { - dispatcher.info(tag ?: tagGenerator.getTag(), message.invoke(), throwable) + val metadata = metadataPool.borrow() + val body = message(metadata) + dispatcher.info(tag ?: tagGenerator.getTag(), body, throwable, metadata) + metadataPool.recycle(metadata) } } /** Send an warn-level log message to the global dispatcher. */ - public fun warn(throwable: Throwable? = null, tag: String? = null, message: () -> String) { + public fun warn(throwable: Throwable? = null, tag: String? = null, message: (WriteMetadata) -> String) { if (dispatcher.hasConsumers) { - dispatcher.warn(tag ?: tagGenerator.getTag(), message.invoke(), throwable) + val metadata = metadataPool.borrow() + val body = message(metadata) + dispatcher.warn(tag ?: tagGenerator.getTag(), body, throwable, metadata) + metadataPool.recycle(metadata) } } /** Send an error-level log message to the global dispatcher. */ - public fun error(throwable: Throwable? = null, tag: String? = null, message: () -> String) { + public fun error(throwable: Throwable? = null, tag: String? = null, message: (WriteMetadata) -> String) { if (dispatcher.hasConsumers) { - dispatcher.error(tag ?: tagGenerator.getTag(), message.invoke(), throwable) + val metadata = metadataPool.borrow() + val body = message(metadata) + dispatcher.error(tag ?: tagGenerator.getTag(), body, throwable, metadata) + metadataPool.recycle(metadata) } } /** Send an assert-level log message to the global dispatcher. */ - public fun assert(throwable: Throwable? = null, tag: String? = null, message: () -> String) { + public fun assert(throwable: Throwable? = null, tag: String? = null, message: (WriteMetadata) -> String) { if (dispatcher.hasConsumers) { - dispatcher.assert(tag ?: tagGenerator.getTag(), message.invoke(), throwable) + val metadata = metadataPool.borrow() + val body = message(metadata) + dispatcher.assert(tag ?: tagGenerator.getTag(), body, throwable, metadata) + metadataPool.recycle(metadata) } } } diff --git a/logging/src/commonMain/kotlin/Logger.kt b/logging/src/commonMain/kotlin/Logger.kt index aef64f13..ad79c47e 100644 --- a/logging/src/commonMain/kotlin/Logger.kt +++ b/logging/src/commonMain/kotlin/Logger.kt @@ -3,21 +3,21 @@ package com.juul.tuulbox.logging /** Classes which implement [Logger] can write logs. */ public interface Logger { - /** Log at verbose-level. */ - public fun verbose(tag: String, message: String, throwable: Throwable?) + /** Log at verbose-level. Do not store a reference to [metadata], create a [copy][ReadMetadata.copy] if you need to. */ + public fun verbose(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) - /** Log at debug-level. */ - public fun debug(tag: String, message: String, throwable: Throwable?) + /** Log at debug-level. Do not store a reference to [metadata], create a [copy][ReadMetadata.copy] if you need to. */ + public fun debug(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) - /** Log at info-level. */ - public fun info(tag: String, message: String, throwable: Throwable?) + /** Log at info-level. Do not store a reference to [metadata], create a [copy][ReadMetadata.copy] if you need to. */ + public fun info(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) - /** Log at warn-level. */ - public fun warn(tag: String, message: String, throwable: Throwable?) + /** Log at warn-level. Do not store a reference to [metadata], create a [copy][ReadMetadata.copy] if you need to. */ + public fun warn(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) - /** Log at error-level. */ - public fun error(tag: String, message: String, throwable: Throwable?) + /** Log at error-level. Do not store a reference to [metadata], create a [copy][ReadMetadata.copy] if you need to. */ + public fun error(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) - /** Log at assert-level. */ - public fun assert(tag: String, message: String, throwable: Throwable?) + /** Log at assert-level. Do not store a reference to [metadata], create a [copy][ReadMetadata.copy] if you need to. */ + public fun assert(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) } diff --git a/logging/src/commonMain/kotlin/Metadata.kt b/logging/src/commonMain/kotlin/Metadata.kt new file mode 100644 index 00000000..adfe063d --- /dev/null +++ b/logging/src/commonMain/kotlin/Metadata.kt @@ -0,0 +1,42 @@ +package com.juul.tuulbox.logging + +internal class Metadata : ReadMetadata, WriteMetadata { + private val storedData = mutableMapOf, Any>() + + @Suppress("UNCHECKED_CAST") + public override operator fun get(key: Key): T? = + storedData[key] as? T + + public override operator fun set(key: Key, value: T) { + storedData[key] = value + } + + public override fun copy(): Metadata = Metadata().also { copy -> + copy.storedData += this.storedData + } + + internal fun clear() { + storedData.clear() + } + + override fun equals(other: Any?): Boolean = other is Metadata && storedData == other.storedData + override fun hashCode(): Int = storedData.hashCode() +} + +/** + * Additional data associated with a log. It's important that [Logger] instances do NOT hold onto references + * to [ReadMetadata] arguments after the function returns. If a [ReadMetadata] reference must be kept after + * function return, create a [copy]. + */ +public interface ReadMetadata { + public operator fun get(key: Key): T? + public fun copy(): ReadMetadata +} + +/** + * Additional data associated with a log. It's important that [Log] calls do NOT hold onto references + * to [WriteMetadata] arguments after the lambda returns. + */ +public interface WriteMetadata { + public operator fun set(key: Key, value: T) +} diff --git a/logging/src/commonMain/kotlin/Pool.kt b/logging/src/commonMain/kotlin/Pool.kt new file mode 100644 index 00000000..33a59435 --- /dev/null +++ b/logging/src/commonMain/kotlin/Pool.kt @@ -0,0 +1,16 @@ +package com.juul.tuulbox.logging + +import kotlinx.atomicfu.locks.reentrantLock +import kotlinx.atomicfu.locks.withLock + +/** While a [Pool] is logically thread safe, Kotlin/Native's memory model requires @ThreadLocal on instances of this. */ +internal class Pool( + private val factory: () -> T, + private val refurbish: (T) -> Unit +) { + private val lock = reentrantLock() + private val cache = ArrayDeque() + + fun borrow(): T = lock.withLock { cache.removeLastOrNull() ?: factory() } + fun recycle(value: T) = lock.withLock { cache.addLast(value.apply(refurbish)) } +} diff --git a/logging/src/commonTest/kotlin/Call.kt b/logging/src/commonTest/kotlin/Call.kt index c69f4a00..4c12c042 100644 --- a/logging/src/commonTest/kotlin/Call.kt +++ b/logging/src/commonTest/kotlin/Call.kt @@ -3,5 +3,6 @@ package com.juul.tuulbox.logging data class Call( val tag: String, val message: String, - val throwable: Throwable? + val throwable: Throwable?, + val metadata: ReadMetadata ) diff --git a/logging/src/commonTest/kotlin/CallListLogger.kt b/logging/src/commonTest/kotlin/CallListLogger.kt index ea9293b0..40c0428f 100644 --- a/logging/src/commonTest/kotlin/CallListLogger.kt +++ b/logging/src/commonTest/kotlin/CallListLogger.kt @@ -23,27 +23,27 @@ class CallListLogger : Logger { private val atomicAssertCalls = atomic(emptyList()) val assertCalls: List get() = atomicAssertCalls.value - override fun verbose(tag: String, message: String, throwable: Throwable?) { - atomicVerboseCalls.getAndUpdate { it + Call(tag = tag, message = message, throwable = throwable) } + override fun verbose(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { + atomicVerboseCalls.getAndUpdate { it + Call(tag = tag, message = message, throwable, metadata.copy()) } } - override fun debug(tag: String, message: String, throwable: Throwable?) { - atomicDebugCalls.getAndUpdate { it + Call(tag = tag, message = message, throwable = throwable) } + override fun debug(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { + atomicDebugCalls.getAndUpdate { it + Call(tag = tag, message = message, throwable, metadata.copy()) } } - override fun info(tag: String, message: String, throwable: Throwable?) { - atomicInfoCalls.getAndUpdate { it + Call(tag = tag, message = message, throwable = throwable) } + override fun info(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { + atomicInfoCalls.getAndUpdate { it + Call(tag = tag, message = message, throwable, metadata.copy()) } } - override fun warn(tag: String, message: String, throwable: Throwable?) { - atomicWarnCalls.getAndUpdate { it + Call(tag = tag, message = message, throwable = throwable) } + override fun warn(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { + atomicWarnCalls.getAndUpdate { it + Call(tag = tag, message = message, throwable, metadata.copy()) } } - override fun error(tag: String, message: String, throwable: Throwable?) { - atomicErrorCalls.getAndUpdate { it + Call(tag = tag, message = message, throwable = throwable) } + override fun error(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { + atomicErrorCalls.getAndUpdate { it + Call(tag = tag, message = message, throwable, metadata.copy()) } } - override fun assert(tag: String, message: String, throwable: Throwable?) { - atomicAssertCalls.getAndUpdate { it + Call(tag = tag, message = message, throwable = throwable) } + override fun assert(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { + atomicAssertCalls.getAndUpdate { it + Call(tag = tag, message = message, throwable, metadata.copy()) } } } diff --git a/logging/src/commonTest/kotlin/DispatchLoggerTests.kt b/logging/src/commonTest/kotlin/DispatchLoggerTests.kt index a7936b56..56dc0177 100644 --- a/logging/src/commonTest/kotlin/DispatchLoggerTests.kt +++ b/logging/src/commonTest/kotlin/DispatchLoggerTests.kt @@ -27,8 +27,9 @@ class DispatchLoggerTests { val second = CallListLogger() dispatcher.install(first) dispatcher.install(second) - val call = Call(tag = "test-tag", message = "test-message", throwable = Throwable()) - dispatcher.verbose(call.tag, call.message, call.throwable) + val metadata = Metadata() + val call = Call(tag = "test-tag", message = "test-message", Throwable(), metadata) + dispatcher.verbose(call.tag, call.message, call.throwable, metadata) assertEquals(call, first.verboseCalls.single()) assertEquals(call, second.verboseCalls.single()) } @@ -40,8 +41,9 @@ class DispatchLoggerTests { val second = CallListLogger() dispatcher.install(first) dispatcher.install(second) - val call = Call(tag = "test-tag", message = "test-message", throwable = Throwable()) - dispatcher.debug(call.tag, call.message, call.throwable) + val metadata = Metadata() + val call = Call(tag = "test-tag", message = "test-message", Throwable(), metadata) + dispatcher.debug(call.tag, call.message, call.throwable, metadata) assertEquals(call, first.debugCalls.single()) assertEquals(call, second.debugCalls.single()) } @@ -53,8 +55,9 @@ class DispatchLoggerTests { val second = CallListLogger() dispatcher.install(first) dispatcher.install(second) - val call = Call(tag = "test-tag", message = "test-message", throwable = Throwable()) - dispatcher.info(call.tag, call.message, call.throwable) + val metadata = Metadata() + val call = Call(tag = "test-tag", message = "test-message", Throwable(), metadata) + dispatcher.info(call.tag, call.message, call.throwable, metadata) assertEquals(call, first.infoCalls.single()) assertEquals(call, second.infoCalls.single()) } @@ -66,8 +69,9 @@ class DispatchLoggerTests { val second = CallListLogger() dispatcher.install(first) dispatcher.install(second) - val call = Call(tag = "test-tag", message = "test-message", throwable = Throwable()) - dispatcher.warn(call.tag, call.message, call.throwable) + val metadata = Metadata() + val call = Call(tag = "test-tag", message = "test-message", Throwable(), metadata) + dispatcher.warn(call.tag, call.message, call.throwable, metadata) assertEquals(call, first.warnCalls.single()) assertEquals(call, second.warnCalls.single()) } @@ -79,8 +83,9 @@ class DispatchLoggerTests { val second = CallListLogger() dispatcher.install(first) dispatcher.install(second) - val call = Call(tag = "test-tag", message = "test-message", throwable = Throwable()) - dispatcher.error(call.tag, call.message, call.throwable) + val metadata = Metadata() + val call = Call(tag = "test-tag", message = "test-message", Throwable(), metadata) + dispatcher.error(call.tag, call.message, call.throwable, metadata) assertEquals(call, first.errorCalls.single()) assertEquals(call, second.errorCalls.single()) } @@ -92,8 +97,9 @@ class DispatchLoggerTests { val second = CallListLogger() dispatcher.install(first) dispatcher.install(second) - val call = Call(tag = "test-tag", message = "test-message", throwable = Throwable()) - dispatcher.assert(call.tag, call.message, call.throwable) + val metadata = Metadata() + val call = Call(tag = "test-tag", message = "test-message", Throwable(), metadata) + dispatcher.assert(call.tag, call.message, call.throwable, metadata) assertEquals(call, first.assertCalls.single()) assertEquals(call, second.assertCalls.single()) } @@ -104,8 +110,9 @@ class DispatchLoggerTests { val consumer = CallListLogger() dispatcher.install(consumer) dispatcher.install(consumer) - val call = Call(tag = "test-tag", message = "test-message", throwable = Throwable()) - dispatcher.verbose(call.tag, call.message, call.throwable) + val metadata = Metadata() + val call = Call(tag = "test-tag", message = "test-message", Throwable(), metadata) + dispatcher.verbose(call.tag, call.message, call.throwable, metadata) assertEquals(call, consumer.verboseCalls.single()) } } diff --git a/logging/src/commonTest/kotlin/MetadataTests.kt b/logging/src/commonTest/kotlin/MetadataTests.kt new file mode 100644 index 00000000..9deaedc3 --- /dev/null +++ b/logging/src/commonTest/kotlin/MetadataTests.kt @@ -0,0 +1,48 @@ +package com.juul.tuulbox.logging + +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertNull +import kotlin.test.assertSame + +object AnyKey : Key +object StringKey : Key +object BooleanKey : Key + +class MetadataTests { + + @Test + fun copy_isShallow() { + val expected = Any() + val metadata = Metadata().also { + it[AnyKey] = expected + } + val actual = metadata.copy()[AnyKey] + assertSame(expected, actual) + } + + @Test + fun get_respectsKeys() { + val metadata = Metadata().also { + it[StringKey] = "test" + it[BooleanKey] = false + } + assertEquals("test", metadata[StringKey]) + assertEquals(false, metadata[BooleanKey]) + } + + @Test + fun get_withNoSet_returnsNull() { + val metadata = Metadata() + assertNull(metadata[StringKey]) + } + + @Test + fun get_afterReset_returnsNull() { + val metadata = Metadata().also { + it[StringKey] = "test" + } + metadata.clear() + assertNull(metadata[StringKey]) + } +} diff --git a/logging/src/jsMain/kotlin/ConsoleLogger.kt b/logging/src/jsMain/kotlin/ConsoleLogger.kt index e752941d..84a5c4e5 100644 --- a/logging/src/jsMain/kotlin/ConsoleLogger.kt +++ b/logging/src/jsMain/kotlin/ConsoleLogger.kt @@ -14,7 +14,7 @@ public actual object ConsoleLogger : Logger { private val simpleMessageFormat = "[%s] %s" private val throwableMessageFormat = "[%s] %s: %o" - override fun verbose(tag: String, message: String, throwable: Throwable?) { + override fun verbose(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { if (throwable == null) { console.asDynamic().debug(simpleMessageFormat, tag, message) } else { @@ -22,7 +22,7 @@ public actual object ConsoleLogger : Logger { } } - override fun debug(tag: String, message: String, throwable: Throwable?) { + override fun debug(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { if (throwable == null) { console.asDynamic().debug(simpleMessageFormat, tag, message) } else { @@ -30,7 +30,7 @@ public actual object ConsoleLogger : Logger { } } - override fun info(tag: String, message: String, throwable: Throwable?) { + override fun info(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { if (throwable == null) { console.info(simpleMessageFormat, tag, message) } else { @@ -38,7 +38,7 @@ public actual object ConsoleLogger : Logger { } } - override fun warn(tag: String, message: String, throwable: Throwable?) { + override fun warn(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { if (throwable == null) { console.warn(simpleMessageFormat, tag, message) } else { @@ -46,7 +46,7 @@ public actual object ConsoleLogger : Logger { } } - override fun error(tag: String, message: String, throwable: Throwable?) { + override fun error(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { if (throwable == null) { console.error(simpleMessageFormat, tag, message) } else { @@ -54,7 +54,7 @@ public actual object ConsoleLogger : Logger { } } - override fun assert(tag: String, message: String, throwable: Throwable?) { + override fun assert(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { if (throwable == null) { console.asDynamic().assert(false, simpleMessageFormat, tag, message) } else { diff --git a/logging/src/jvmMain/kotlin/ConsoleLogger.kt b/logging/src/jvmMain/kotlin/ConsoleLogger.kt index d5ca3493..025f5249 100644 --- a/logging/src/jvmMain/kotlin/ConsoleLogger.kt +++ b/logging/src/jvmMain/kotlin/ConsoleLogger.kt @@ -21,27 +21,27 @@ public actual object ConsoleLogger : Logger { } } - override fun verbose(tag: String, message: String, throwable: Throwable?) { + override fun verbose(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { print(System.out, "V", tag, message, throwable) } - override fun debug(tag: String, message: String, throwable: Throwable?) { + override fun debug(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { print(System.out, "D", tag, message, throwable) } - override fun info(tag: String, message: String, throwable: Throwable?) { + override fun info(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { print(System.out, "I", tag, message, throwable) } - override fun warn(tag: String, message: String, throwable: Throwable?) { + override fun warn(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { print(System.out, "W", tag, message, throwable) } - override fun error(tag: String, message: String, throwable: Throwable?) { + override fun error(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { print(System.err, "E", tag, message, throwable) } - override fun assert(tag: String, message: String, throwable: Throwable?) { + override fun assert(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { print(System.err, "A", tag, message, throwable) } } diff --git a/logging/src/jvmTest/kotlin/ConsoleLoggerTests.kt b/logging/src/jvmTest/kotlin/ConsoleLoggerTests.kt index cb4566de..20f2b530 100644 --- a/logging/src/jvmTest/kotlin/ConsoleLoggerTests.kt +++ b/logging/src/jvmTest/kotlin/ConsoleLoggerTests.kt @@ -42,7 +42,7 @@ class ConsoleLoggerTests { @Test fun checkVerboseWithoutThrowable() { - ConsoleLogger.verbose(TAG, MESSAGE, null) + ConsoleLogger.verbose(TAG, MESSAGE, null, Metadata()) val logString = testOutBuffer.toString(UTF8) assertTrue(TAG in logString) assertTrue(MESSAGE in logString) @@ -51,7 +51,7 @@ class ConsoleLoggerTests { @Test fun checkVerboseWithThrowable() { val throwable = Throwable() - ConsoleLogger.verbose(TAG, MESSAGE, throwable) + ConsoleLogger.verbose(TAG, MESSAGE, throwable, Metadata()) val logString = testOutBuffer.toString(UTF8) assertTrue(TAG in logString) assertTrue(MESSAGE in logString) @@ -60,7 +60,7 @@ class ConsoleLoggerTests { @Test fun checkDebugWithoutThrowable() { - ConsoleLogger.debug(TAG, MESSAGE, null) + ConsoleLogger.debug(TAG, MESSAGE, null, Metadata()) val logString = testOutBuffer.toString(UTF8) assertTrue(TAG in logString) assertTrue(MESSAGE in logString) @@ -69,7 +69,7 @@ class ConsoleLoggerTests { @Test fun checkDebugWithThrowable() { val throwable = Throwable() - ConsoleLogger.debug(TAG, MESSAGE, throwable) + ConsoleLogger.debug(TAG, MESSAGE, throwable, Metadata()) val logString = testOutBuffer.toString(UTF8) assertTrue(TAG in logString) assertTrue(MESSAGE in logString) @@ -78,7 +78,7 @@ class ConsoleLoggerTests { @Test fun checkInfoWithoutThrowable() { - ConsoleLogger.info(TAG, MESSAGE, null) + ConsoleLogger.info(TAG, MESSAGE, null, Metadata()) val logString = testOutBuffer.toString(UTF8) assertTrue(TAG in logString) assertTrue(MESSAGE in logString) @@ -87,7 +87,7 @@ class ConsoleLoggerTests { @Test fun checkInfoWithThrowable() { val throwable = Throwable() - ConsoleLogger.info(TAG, MESSAGE, throwable) + ConsoleLogger.info(TAG, MESSAGE, throwable, Metadata()) val logString = testOutBuffer.toString(UTF8) assertTrue(TAG in logString) assertTrue(MESSAGE in logString) @@ -96,7 +96,7 @@ class ConsoleLoggerTests { @Test fun checkWarnWithoutThrowable() { - ConsoleLogger.warn(TAG, MESSAGE, null) + ConsoleLogger.warn(TAG, MESSAGE, null, Metadata()) val logString = testOutBuffer.toString(UTF8) assertTrue(TAG in logString) assertTrue(MESSAGE in logString) @@ -105,7 +105,7 @@ class ConsoleLoggerTests { @Test fun checkWarnWithThrowable() { val throwable = Throwable() - ConsoleLogger.warn(TAG, MESSAGE, throwable) + ConsoleLogger.warn(TAG, MESSAGE, throwable, Metadata()) val logString = testOutBuffer.toString(UTF8) assertTrue(TAG in logString) assertTrue(MESSAGE in logString) @@ -114,7 +114,7 @@ class ConsoleLoggerTests { @Test fun checkErrorWithoutThrowable() { - ConsoleLogger.error(TAG, MESSAGE, null) + ConsoleLogger.error(TAG, MESSAGE, null, Metadata()) val logString = testErrBuffer.toString(UTF8) assertTrue(TAG in logString) assertTrue(MESSAGE in logString) @@ -123,7 +123,7 @@ class ConsoleLoggerTests { @Test fun checkErrorWithThrowable() { val throwable = Throwable() - ConsoleLogger.error(TAG, MESSAGE, throwable) + ConsoleLogger.error(TAG, MESSAGE, throwable, Metadata()) val logString = testErrBuffer.toString(UTF8) assertTrue(TAG in logString) assertTrue(MESSAGE in logString) @@ -132,7 +132,7 @@ class ConsoleLoggerTests { @Test fun checkAssertWithoutThrowable() { - ConsoleLogger.assert(TAG, MESSAGE, null) + ConsoleLogger.assert(TAG, MESSAGE, null, Metadata()) val logString = testErrBuffer.toString(UTF8) assertTrue(TAG in logString) assertTrue(MESSAGE in logString) @@ -141,7 +141,7 @@ class ConsoleLoggerTests { @Test fun checkAssertWithThrowable() { val throwable = Throwable() - ConsoleLogger.assert(TAG, MESSAGE, throwable) + ConsoleLogger.assert(TAG, MESSAGE, throwable, Metadata()) val logString = testErrBuffer.toString(UTF8) assertTrue(TAG in logString) assertTrue(MESSAGE in logString) diff --git a/logging/src/macosX64Main/kotlin/ConsoleLogger.kt b/logging/src/macosX64Main/kotlin/ConsoleLogger.kt index 1a1393c1..95d2fad2 100644 --- a/logging/src/macosX64Main/kotlin/ConsoleLogger.kt +++ b/logging/src/macosX64Main/kotlin/ConsoleLogger.kt @@ -32,27 +32,27 @@ public actual object ConsoleLogger : Logger { fflush(stream) } - override fun verbose(tag: String, message: String, throwable: Throwable?) { + override fun verbose(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { print(stdout, "V", tag, message, throwable) } - override fun debug(tag: String, message: String, throwable: Throwable?) { + override fun debug(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { print(stdout, "D", tag, message, throwable) } - override fun info(tag: String, message: String, throwable: Throwable?) { + override fun info(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { print(stdout, "I", tag, message, throwable) } - override fun warn(tag: String, message: String, throwable: Throwable?) { + override fun warn(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { print(stdout, "W", tag, message, throwable) } - override fun error(tag: String, message: String, throwable: Throwable?) { + override fun error(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { print(stderr, "E", tag, message, throwable) } - override fun assert(tag: String, message: String, throwable: Throwable?) { + override fun assert(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { print(stderr, "A", tag, message, throwable) } } From 19f3c5281e89775557b88605393a4ac4ef467dff Mon Sep 17 00:00:00 2001 From: Cedrick Cooke Date: Tue, 13 Apr 2021 17:29:13 -0700 Subject: [PATCH 2/3] Change argument order so metadata comes before throwable --- logging/api/logging.api | 36 +++++++++---------- .../src/commonMain/kotlin/DispatchLogger.kt | 24 ++++++------- logging/src/commonMain/kotlin/Log.kt | 14 ++++---- logging/src/commonMain/kotlin/Logger.kt | 12 +++---- .../src/commonTest/kotlin/CallListLogger.kt | 14 ++++---- .../commonTest/kotlin/DispatchLoggerTests.kt | 14 ++++---- logging/src/commonTest/kotlin/Keys.kt | 5 +++ logging/src/commonTest/kotlin/LogTests.kt | 17 +++++++++ .../src/commonTest/kotlin/MetadataTests.kt | 4 --- logging/src/jsMain/kotlin/ConsoleLogger.kt | 12 +++---- logging/src/jvmMain/kotlin/ConsoleLogger.kt | 12 +++---- .../src/jvmTest/kotlin/ConsoleLoggerTests.kt | 24 ++++++------- .../src/macosX64Main/kotlin/ConsoleLogger.kt | 12 +++---- 13 files changed, 109 insertions(+), 91 deletions(-) create mode 100644 logging/src/commonTest/kotlin/Keys.kt diff --git a/logging/api/logging.api b/logging/api/logging.api index e1b64deb..2b9adf2f 100644 --- a/logging/api/logging.api +++ b/logging/api/logging.api @@ -1,11 +1,11 @@ public final class com/juul/tuulbox/logging/ConsoleLogger : com/juul/tuulbox/logging/Logger { public static final field INSTANCE Lcom/juul/tuulbox/logging/ConsoleLogger; - public fun assert (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Lcom/juul/tuulbox/logging/ReadMetadata;)V - public fun debug (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Lcom/juul/tuulbox/logging/ReadMetadata;)V - public fun error (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Lcom/juul/tuulbox/logging/ReadMetadata;)V - public fun info (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Lcom/juul/tuulbox/logging/ReadMetadata;)V - public fun verbose (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Lcom/juul/tuulbox/logging/ReadMetadata;)V - public fun warn (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Lcom/juul/tuulbox/logging/ReadMetadata;)V + public fun assert (Ljava/lang/String;Ljava/lang/String;Lcom/juul/tuulbox/logging/ReadMetadata;Ljava/lang/Throwable;)V + public fun debug (Ljava/lang/String;Ljava/lang/String;Lcom/juul/tuulbox/logging/ReadMetadata;Ljava/lang/Throwable;)V + public fun error (Ljava/lang/String;Ljava/lang/String;Lcom/juul/tuulbox/logging/ReadMetadata;Ljava/lang/Throwable;)V + public fun info (Ljava/lang/String;Ljava/lang/String;Lcom/juul/tuulbox/logging/ReadMetadata;Ljava/lang/Throwable;)V + public fun verbose (Ljava/lang/String;Ljava/lang/String;Lcom/juul/tuulbox/logging/ReadMetadata;Ljava/lang/Throwable;)V + public fun warn (Ljava/lang/String;Ljava/lang/String;Lcom/juul/tuulbox/logging/ReadMetadata;Ljava/lang/Throwable;)V } public final class com/juul/tuulbox/logging/ConstantTagGenerator : com/juul/tuulbox/logging/TagGenerator { @@ -15,14 +15,14 @@ public final class com/juul/tuulbox/logging/ConstantTagGenerator : com/juul/tuul public final class com/juul/tuulbox/logging/DispatchLogger : com/juul/tuulbox/logging/Logger { public fun ()V - public fun assert (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Lcom/juul/tuulbox/logging/ReadMetadata;)V + public fun assert (Ljava/lang/String;Ljava/lang/String;Lcom/juul/tuulbox/logging/ReadMetadata;Ljava/lang/Throwable;)V public final fun clear ()V - public fun debug (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Lcom/juul/tuulbox/logging/ReadMetadata;)V - public fun error (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Lcom/juul/tuulbox/logging/ReadMetadata;)V - public fun info (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Lcom/juul/tuulbox/logging/ReadMetadata;)V + public fun debug (Ljava/lang/String;Ljava/lang/String;Lcom/juul/tuulbox/logging/ReadMetadata;Ljava/lang/Throwable;)V + public fun error (Ljava/lang/String;Ljava/lang/String;Lcom/juul/tuulbox/logging/ReadMetadata;Ljava/lang/Throwable;)V + public fun info (Ljava/lang/String;Ljava/lang/String;Lcom/juul/tuulbox/logging/ReadMetadata;Ljava/lang/Throwable;)V public final fun install (Lcom/juul/tuulbox/logging/Logger;)V - public fun verbose (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Lcom/juul/tuulbox/logging/ReadMetadata;)V - public fun warn (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Lcom/juul/tuulbox/logging/ReadMetadata;)V + public fun verbose (Ljava/lang/String;Ljava/lang/String;Lcom/juul/tuulbox/logging/ReadMetadata;Ljava/lang/Throwable;)V + public fun warn (Ljava/lang/String;Ljava/lang/String;Lcom/juul/tuulbox/logging/ReadMetadata;Ljava/lang/Throwable;)V } public abstract interface class com/juul/tuulbox/logging/Key { @@ -48,12 +48,12 @@ public final class com/juul/tuulbox/logging/Log { } public abstract interface class com/juul/tuulbox/logging/Logger { - public abstract fun assert (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Lcom/juul/tuulbox/logging/ReadMetadata;)V - public abstract fun debug (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Lcom/juul/tuulbox/logging/ReadMetadata;)V - public abstract fun error (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Lcom/juul/tuulbox/logging/ReadMetadata;)V - public abstract fun info (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Lcom/juul/tuulbox/logging/ReadMetadata;)V - public abstract fun verbose (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Lcom/juul/tuulbox/logging/ReadMetadata;)V - public abstract fun warn (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Lcom/juul/tuulbox/logging/ReadMetadata;)V + public abstract fun assert (Ljava/lang/String;Ljava/lang/String;Lcom/juul/tuulbox/logging/ReadMetadata;Ljava/lang/Throwable;)V + public abstract fun debug (Ljava/lang/String;Ljava/lang/String;Lcom/juul/tuulbox/logging/ReadMetadata;Ljava/lang/Throwable;)V + public abstract fun error (Ljava/lang/String;Ljava/lang/String;Lcom/juul/tuulbox/logging/ReadMetadata;Ljava/lang/Throwable;)V + public abstract fun info (Ljava/lang/String;Ljava/lang/String;Lcom/juul/tuulbox/logging/ReadMetadata;Ljava/lang/Throwable;)V + public abstract fun verbose (Ljava/lang/String;Ljava/lang/String;Lcom/juul/tuulbox/logging/ReadMetadata;Ljava/lang/Throwable;)V + public abstract fun warn (Ljava/lang/String;Ljava/lang/String;Lcom/juul/tuulbox/logging/ReadMetadata;Ljava/lang/Throwable;)V } public abstract interface class com/juul/tuulbox/logging/ReadMetadata { diff --git a/logging/src/commonMain/kotlin/DispatchLogger.kt b/logging/src/commonMain/kotlin/DispatchLogger.kt index 573571a5..58519210 100644 --- a/logging/src/commonMain/kotlin/DispatchLogger.kt +++ b/logging/src/commonMain/kotlin/DispatchLogger.kt @@ -21,27 +21,27 @@ public class DispatchLogger : Logger { consumers.value = emptySet() } - override fun verbose(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { - consumers.value.forEach { it.verbose(tag, message, throwable, metadata) } + override fun verbose(tag: String, message: String, metadata: ReadMetadata, throwable: Throwable?) { + consumers.value.forEach { it.verbose(tag, message, metadata, throwable) } } - override fun debug(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { - consumers.value.forEach { it.debug(tag, message, throwable, metadata) } + override fun debug(tag: String, message: String, metadata: ReadMetadata, throwable: Throwable?) { + consumers.value.forEach { it.debug(tag, message, metadata, throwable) } } - override fun info(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { - consumers.value.forEach { it.info(tag, message, throwable, metadata) } + override fun info(tag: String, message: String, metadata: ReadMetadata, throwable: Throwable?) { + consumers.value.forEach { it.info(tag, message, metadata, throwable) } } - override fun warn(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { - consumers.value.forEach { it.warn(tag, message, throwable, metadata) } + override fun warn(tag: String, message: String, metadata: ReadMetadata, throwable: Throwable?) { + consumers.value.forEach { it.warn(tag, message, metadata, throwable) } } - override fun error(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { - consumers.value.forEach { it.error(tag, message, throwable, metadata) } + override fun error(tag: String, message: String, metadata: ReadMetadata, throwable: Throwable?) { + consumers.value.forEach { it.error(tag, message, metadata, throwable) } } - override fun assert(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { - consumers.value.forEach { it.assert(tag, message, throwable, metadata) } + override fun assert(tag: String, message: String, metadata: ReadMetadata, throwable: Throwable?) { + consumers.value.forEach { it.assert(tag, message, metadata, throwable) } } } diff --git a/logging/src/commonMain/kotlin/Log.kt b/logging/src/commonMain/kotlin/Log.kt index 6e915345..fc869632 100644 --- a/logging/src/commonMain/kotlin/Log.kt +++ b/logging/src/commonMain/kotlin/Log.kt @@ -4,7 +4,7 @@ import com.juul.tuulbox.logging.Log.dispatcher import kotlinx.atomicfu.atomic import kotlin.native.concurrent.ThreadLocal -@ThreadLocal // Pool mutates internal state, easiest solution is to thread-local this in Kotlin/Native. +@ThreadLocal // Thread local pool means that metadata returned from it are safe to mutate on that same thread. private val metadataPool = Pool(factory = ::Metadata, refurbish = Metadata::clear) /** Global logging object. To receive logs, call [dispatcher].[install][DispatchLogger.install]. */ @@ -27,7 +27,7 @@ public object Log { if (dispatcher.hasConsumers) { val metadata = metadataPool.borrow() val body = message(metadata) - dispatcher.verbose(tag ?: tagGenerator.getTag(), body, throwable, metadata) + dispatcher.verbose(tag ?: tagGenerator.getTag(), body, metadata, throwable) metadataPool.recycle(metadata) } } @@ -37,7 +37,7 @@ public object Log { if (dispatcher.hasConsumers) { val metadata = metadataPool.borrow() val body = message(metadata) - dispatcher.debug(tag ?: tagGenerator.getTag(), body, throwable, metadata) + dispatcher.debug(tag ?: tagGenerator.getTag(), body, metadata, throwable) metadataPool.recycle(metadata) } } @@ -47,7 +47,7 @@ public object Log { if (dispatcher.hasConsumers) { val metadata = metadataPool.borrow() val body = message(metadata) - dispatcher.info(tag ?: tagGenerator.getTag(), body, throwable, metadata) + dispatcher.info(tag ?: tagGenerator.getTag(), body, metadata, throwable) metadataPool.recycle(metadata) } } @@ -57,7 +57,7 @@ public object Log { if (dispatcher.hasConsumers) { val metadata = metadataPool.borrow() val body = message(metadata) - dispatcher.warn(tag ?: tagGenerator.getTag(), body, throwable, metadata) + dispatcher.warn(tag ?: tagGenerator.getTag(), body, metadata, throwable) metadataPool.recycle(metadata) } } @@ -67,7 +67,7 @@ public object Log { if (dispatcher.hasConsumers) { val metadata = metadataPool.borrow() val body = message(metadata) - dispatcher.error(tag ?: tagGenerator.getTag(), body, throwable, metadata) + dispatcher.error(tag ?: tagGenerator.getTag(), body, metadata, throwable) metadataPool.recycle(metadata) } } @@ -77,7 +77,7 @@ public object Log { if (dispatcher.hasConsumers) { val metadata = metadataPool.borrow() val body = message(metadata) - dispatcher.assert(tag ?: tagGenerator.getTag(), body, throwable, metadata) + dispatcher.assert(tag ?: tagGenerator.getTag(), body, metadata, throwable) metadataPool.recycle(metadata) } } diff --git a/logging/src/commonMain/kotlin/Logger.kt b/logging/src/commonMain/kotlin/Logger.kt index ad79c47e..f05aa53d 100644 --- a/logging/src/commonMain/kotlin/Logger.kt +++ b/logging/src/commonMain/kotlin/Logger.kt @@ -4,20 +4,20 @@ package com.juul.tuulbox.logging public interface Logger { /** Log at verbose-level. Do not store a reference to [metadata], create a [copy][ReadMetadata.copy] if you need to. */ - public fun verbose(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) + public fun verbose(tag: String, message: String, metadata: ReadMetadata, throwable: Throwable?) /** Log at debug-level. Do not store a reference to [metadata], create a [copy][ReadMetadata.copy] if you need to. */ - public fun debug(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) + public fun debug(tag: String, message: String, metadata: ReadMetadata, throwable: Throwable?) /** Log at info-level. Do not store a reference to [metadata], create a [copy][ReadMetadata.copy] if you need to. */ - public fun info(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) + public fun info(tag: String, message: String, metadata: ReadMetadata, throwable: Throwable?) /** Log at warn-level. Do not store a reference to [metadata], create a [copy][ReadMetadata.copy] if you need to. */ - public fun warn(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) + public fun warn(tag: String, message: String, metadata: ReadMetadata, throwable: Throwable?) /** Log at error-level. Do not store a reference to [metadata], create a [copy][ReadMetadata.copy] if you need to. */ - public fun error(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) + public fun error(tag: String, message: String, metadata: ReadMetadata, throwable: Throwable?) /** Log at assert-level. Do not store a reference to [metadata], create a [copy][ReadMetadata.copy] if you need to. */ - public fun assert(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) + public fun assert(tag: String, message: String, metadata: ReadMetadata, throwable: Throwable?) } diff --git a/logging/src/commonTest/kotlin/CallListLogger.kt b/logging/src/commonTest/kotlin/CallListLogger.kt index 40c0428f..a85c59ac 100644 --- a/logging/src/commonTest/kotlin/CallListLogger.kt +++ b/logging/src/commonTest/kotlin/CallListLogger.kt @@ -3,7 +3,7 @@ package com.juul.tuulbox.logging import kotlinx.atomicfu.atomic import kotlinx.atomicfu.getAndUpdate -class CallListLogger : Logger { +open class CallListLogger : Logger { private val atomicVerboseCalls = atomic(emptyList()) val verboseCalls: List get() = atomicVerboseCalls.value @@ -23,27 +23,27 @@ class CallListLogger : Logger { private val atomicAssertCalls = atomic(emptyList()) val assertCalls: List get() = atomicAssertCalls.value - override fun verbose(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { + override fun verbose(tag: String, message: String, metadata: ReadMetadata, throwable: Throwable?) { atomicVerboseCalls.getAndUpdate { it + Call(tag = tag, message = message, throwable, metadata.copy()) } } - override fun debug(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { + override fun debug(tag: String, message: String, metadata: ReadMetadata, throwable: Throwable?) { atomicDebugCalls.getAndUpdate { it + Call(tag = tag, message = message, throwable, metadata.copy()) } } - override fun info(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { + override fun info(tag: String, message: String, metadata: ReadMetadata, throwable: Throwable?) { atomicInfoCalls.getAndUpdate { it + Call(tag = tag, message = message, throwable, metadata.copy()) } } - override fun warn(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { + override fun warn(tag: String, message: String, metadata: ReadMetadata, throwable: Throwable?) { atomicWarnCalls.getAndUpdate { it + Call(tag = tag, message = message, throwable, metadata.copy()) } } - override fun error(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { + override fun error(tag: String, message: String, metadata: ReadMetadata, throwable: Throwable?) { atomicErrorCalls.getAndUpdate { it + Call(tag = tag, message = message, throwable, metadata.copy()) } } - override fun assert(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { + override fun assert(tag: String, message: String, metadata: ReadMetadata, throwable: Throwable?) { atomicAssertCalls.getAndUpdate { it + Call(tag = tag, message = message, throwable, metadata.copy()) } } } diff --git a/logging/src/commonTest/kotlin/DispatchLoggerTests.kt b/logging/src/commonTest/kotlin/DispatchLoggerTests.kt index 56dc0177..a7e12e40 100644 --- a/logging/src/commonTest/kotlin/DispatchLoggerTests.kt +++ b/logging/src/commonTest/kotlin/DispatchLoggerTests.kt @@ -29,7 +29,7 @@ class DispatchLoggerTests { dispatcher.install(second) val metadata = Metadata() val call = Call(tag = "test-tag", message = "test-message", Throwable(), metadata) - dispatcher.verbose(call.tag, call.message, call.throwable, metadata) + dispatcher.verbose(call.tag, call.message, metadata, call.throwable) assertEquals(call, first.verboseCalls.single()) assertEquals(call, second.verboseCalls.single()) } @@ -43,7 +43,7 @@ class DispatchLoggerTests { dispatcher.install(second) val metadata = Metadata() val call = Call(tag = "test-tag", message = "test-message", Throwable(), metadata) - dispatcher.debug(call.tag, call.message, call.throwable, metadata) + dispatcher.debug(call.tag, call.message, metadata, call.throwable) assertEquals(call, first.debugCalls.single()) assertEquals(call, second.debugCalls.single()) } @@ -57,7 +57,7 @@ class DispatchLoggerTests { dispatcher.install(second) val metadata = Metadata() val call = Call(tag = "test-tag", message = "test-message", Throwable(), metadata) - dispatcher.info(call.tag, call.message, call.throwable, metadata) + dispatcher.info(call.tag, call.message, metadata, call.throwable) assertEquals(call, first.infoCalls.single()) assertEquals(call, second.infoCalls.single()) } @@ -71,7 +71,7 @@ class DispatchLoggerTests { dispatcher.install(second) val metadata = Metadata() val call = Call(tag = "test-tag", message = "test-message", Throwable(), metadata) - dispatcher.warn(call.tag, call.message, call.throwable, metadata) + dispatcher.warn(call.tag, call.message, metadata, call.throwable) assertEquals(call, first.warnCalls.single()) assertEquals(call, second.warnCalls.single()) } @@ -85,7 +85,7 @@ class DispatchLoggerTests { dispatcher.install(second) val metadata = Metadata() val call = Call(tag = "test-tag", message = "test-message", Throwable(), metadata) - dispatcher.error(call.tag, call.message, call.throwable, metadata) + dispatcher.error(call.tag, call.message, metadata, call.throwable) assertEquals(call, first.errorCalls.single()) assertEquals(call, second.errorCalls.single()) } @@ -99,7 +99,7 @@ class DispatchLoggerTests { dispatcher.install(second) val metadata = Metadata() val call = Call(tag = "test-tag", message = "test-message", Throwable(), metadata) - dispatcher.assert(call.tag, call.message, call.throwable, metadata) + dispatcher.assert(call.tag, call.message, metadata, call.throwable) assertEquals(call, first.assertCalls.single()) assertEquals(call, second.assertCalls.single()) } @@ -112,7 +112,7 @@ class DispatchLoggerTests { dispatcher.install(consumer) val metadata = Metadata() val call = Call(tag = "test-tag", message = "test-message", Throwable(), metadata) - dispatcher.verbose(call.tag, call.message, call.throwable, metadata) + dispatcher.verbose(call.tag, call.message, metadata, call.throwable) assertEquals(call, consumer.verboseCalls.single()) } } diff --git a/logging/src/commonTest/kotlin/Keys.kt b/logging/src/commonTest/kotlin/Keys.kt new file mode 100644 index 00000000..312c449f --- /dev/null +++ b/logging/src/commonTest/kotlin/Keys.kt @@ -0,0 +1,5 @@ +package com.juul.tuulbox.logging + +internal object AnyKey : Key +internal object StringKey : Key +internal object BooleanKey : Key diff --git a/logging/src/commonTest/kotlin/LogTests.kt b/logging/src/commonTest/kotlin/LogTests.kt index 4771c33c..b3c67cdd 100644 --- a/logging/src/commonTest/kotlin/LogTests.kt +++ b/logging/src/commonTest/kotlin/LogTests.kt @@ -2,6 +2,7 @@ package com.juul.tuulbox.logging import kotlin.test.AfterTest import kotlin.test.Test +import kotlin.test.assertEquals import kotlin.test.assertSame import kotlin.test.assertTrue import kotlin.test.fail @@ -158,4 +159,20 @@ class LogTests { Log.assert(tag = "explicit tag") { "Test message" } assertTrue { logger.assertCalls.all { it.tag == "explicit tag" } } } + + @Test + fun verbose_withMetadata_canReadInLogger() { + Log.tagGenerator = failTestTagGenerator + val logger = object : CallListLogger() { + override fun verbose(tag: String, message: String, metadata: ReadMetadata, throwable: Throwable?) { + super.verbose(tag, message, metadata, throwable) + assertEquals("test", metadata[StringKey]) + } + } + Log.dispatcher.install(logger) + Log.verbose(tag = "explicit tag") { metadata -> + metadata[StringKey] = "test" + "Test message" + } + } } diff --git a/logging/src/commonTest/kotlin/MetadataTests.kt b/logging/src/commonTest/kotlin/MetadataTests.kt index 9deaedc3..0b22f861 100644 --- a/logging/src/commonTest/kotlin/MetadataTests.kt +++ b/logging/src/commonTest/kotlin/MetadataTests.kt @@ -5,10 +5,6 @@ import kotlin.test.assertEquals import kotlin.test.assertNull import kotlin.test.assertSame -object AnyKey : Key -object StringKey : Key -object BooleanKey : Key - class MetadataTests { @Test diff --git a/logging/src/jsMain/kotlin/ConsoleLogger.kt b/logging/src/jsMain/kotlin/ConsoleLogger.kt index 84a5c4e5..b6cf4267 100644 --- a/logging/src/jsMain/kotlin/ConsoleLogger.kt +++ b/logging/src/jsMain/kotlin/ConsoleLogger.kt @@ -14,7 +14,7 @@ public actual object ConsoleLogger : Logger { private val simpleMessageFormat = "[%s] %s" private val throwableMessageFormat = "[%s] %s: %o" - override fun verbose(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { + override fun verbose(tag: String, message: String, metadata: ReadMetadata, throwable: Throwable?) { if (throwable == null) { console.asDynamic().debug(simpleMessageFormat, tag, message) } else { @@ -22,7 +22,7 @@ public actual object ConsoleLogger : Logger { } } - override fun debug(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { + override fun debug(tag: String, message: String, metadata: ReadMetadata, throwable: Throwable?) { if (throwable == null) { console.asDynamic().debug(simpleMessageFormat, tag, message) } else { @@ -30,7 +30,7 @@ public actual object ConsoleLogger : Logger { } } - override fun info(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { + override fun info(tag: String, message: String, metadata: ReadMetadata, throwable: Throwable?) { if (throwable == null) { console.info(simpleMessageFormat, tag, message) } else { @@ -38,7 +38,7 @@ public actual object ConsoleLogger : Logger { } } - override fun warn(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { + override fun warn(tag: String, message: String, metadata: ReadMetadata, throwable: Throwable?) { if (throwable == null) { console.warn(simpleMessageFormat, tag, message) } else { @@ -46,7 +46,7 @@ public actual object ConsoleLogger : Logger { } } - override fun error(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { + override fun error(tag: String, message: String, metadata: ReadMetadata, throwable: Throwable?) { if (throwable == null) { console.error(simpleMessageFormat, tag, message) } else { @@ -54,7 +54,7 @@ public actual object ConsoleLogger : Logger { } } - override fun assert(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { + override fun assert(tag: String, message: String, metadata: ReadMetadata, throwable: Throwable?) { if (throwable == null) { console.asDynamic().assert(false, simpleMessageFormat, tag, message) } else { diff --git a/logging/src/jvmMain/kotlin/ConsoleLogger.kt b/logging/src/jvmMain/kotlin/ConsoleLogger.kt index 025f5249..c535bc91 100644 --- a/logging/src/jvmMain/kotlin/ConsoleLogger.kt +++ b/logging/src/jvmMain/kotlin/ConsoleLogger.kt @@ -21,27 +21,27 @@ public actual object ConsoleLogger : Logger { } } - override fun verbose(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { + override fun verbose(tag: String, message: String, metadata: ReadMetadata, throwable: Throwable?) { print(System.out, "V", tag, message, throwable) } - override fun debug(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { + override fun debug(tag: String, message: String, metadata: ReadMetadata, throwable: Throwable?) { print(System.out, "D", tag, message, throwable) } - override fun info(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { + override fun info(tag: String, message: String, metadata: ReadMetadata, throwable: Throwable?) { print(System.out, "I", tag, message, throwable) } - override fun warn(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { + override fun warn(tag: String, message: String, metadata: ReadMetadata, throwable: Throwable?) { print(System.out, "W", tag, message, throwable) } - override fun error(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { + override fun error(tag: String, message: String, metadata: ReadMetadata, throwable: Throwable?) { print(System.err, "E", tag, message, throwable) } - override fun assert(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { + override fun assert(tag: String, message: String, metadata: ReadMetadata, throwable: Throwable?) { print(System.err, "A", tag, message, throwable) } } diff --git a/logging/src/jvmTest/kotlin/ConsoleLoggerTests.kt b/logging/src/jvmTest/kotlin/ConsoleLoggerTests.kt index 20f2b530..9871b7ce 100644 --- a/logging/src/jvmTest/kotlin/ConsoleLoggerTests.kt +++ b/logging/src/jvmTest/kotlin/ConsoleLoggerTests.kt @@ -42,7 +42,7 @@ class ConsoleLoggerTests { @Test fun checkVerboseWithoutThrowable() { - ConsoleLogger.verbose(TAG, MESSAGE, null, Metadata()) + ConsoleLogger.verbose(TAG, MESSAGE, Metadata(), null) val logString = testOutBuffer.toString(UTF8) assertTrue(TAG in logString) assertTrue(MESSAGE in logString) @@ -51,7 +51,7 @@ class ConsoleLoggerTests { @Test fun checkVerboseWithThrowable() { val throwable = Throwable() - ConsoleLogger.verbose(TAG, MESSAGE, throwable, Metadata()) + ConsoleLogger.verbose(TAG, MESSAGE, Metadata(), throwable) val logString = testOutBuffer.toString(UTF8) assertTrue(TAG in logString) assertTrue(MESSAGE in logString) @@ -60,7 +60,7 @@ class ConsoleLoggerTests { @Test fun checkDebugWithoutThrowable() { - ConsoleLogger.debug(TAG, MESSAGE, null, Metadata()) + ConsoleLogger.debug(TAG, MESSAGE, Metadata(), null) val logString = testOutBuffer.toString(UTF8) assertTrue(TAG in logString) assertTrue(MESSAGE in logString) @@ -69,7 +69,7 @@ class ConsoleLoggerTests { @Test fun checkDebugWithThrowable() { val throwable = Throwable() - ConsoleLogger.debug(TAG, MESSAGE, throwable, Metadata()) + ConsoleLogger.debug(TAG, MESSAGE, Metadata(), throwable) val logString = testOutBuffer.toString(UTF8) assertTrue(TAG in logString) assertTrue(MESSAGE in logString) @@ -78,7 +78,7 @@ class ConsoleLoggerTests { @Test fun checkInfoWithoutThrowable() { - ConsoleLogger.info(TAG, MESSAGE, null, Metadata()) + ConsoleLogger.info(TAG, MESSAGE, Metadata(), null) val logString = testOutBuffer.toString(UTF8) assertTrue(TAG in logString) assertTrue(MESSAGE in logString) @@ -87,7 +87,7 @@ class ConsoleLoggerTests { @Test fun checkInfoWithThrowable() { val throwable = Throwable() - ConsoleLogger.info(TAG, MESSAGE, throwable, Metadata()) + ConsoleLogger.info(TAG, MESSAGE, Metadata(), throwable) val logString = testOutBuffer.toString(UTF8) assertTrue(TAG in logString) assertTrue(MESSAGE in logString) @@ -96,7 +96,7 @@ class ConsoleLoggerTests { @Test fun checkWarnWithoutThrowable() { - ConsoleLogger.warn(TAG, MESSAGE, null, Metadata()) + ConsoleLogger.warn(TAG, MESSAGE, Metadata(), null) val logString = testOutBuffer.toString(UTF8) assertTrue(TAG in logString) assertTrue(MESSAGE in logString) @@ -105,7 +105,7 @@ class ConsoleLoggerTests { @Test fun checkWarnWithThrowable() { val throwable = Throwable() - ConsoleLogger.warn(TAG, MESSAGE, throwable, Metadata()) + ConsoleLogger.warn(TAG, MESSAGE, Metadata(), throwable) val logString = testOutBuffer.toString(UTF8) assertTrue(TAG in logString) assertTrue(MESSAGE in logString) @@ -114,7 +114,7 @@ class ConsoleLoggerTests { @Test fun checkErrorWithoutThrowable() { - ConsoleLogger.error(TAG, MESSAGE, null, Metadata()) + ConsoleLogger.error(TAG, MESSAGE, Metadata(), null) val logString = testErrBuffer.toString(UTF8) assertTrue(TAG in logString) assertTrue(MESSAGE in logString) @@ -123,7 +123,7 @@ class ConsoleLoggerTests { @Test fun checkErrorWithThrowable() { val throwable = Throwable() - ConsoleLogger.error(TAG, MESSAGE, throwable, Metadata()) + ConsoleLogger.error(TAG, MESSAGE, Metadata(), throwable) val logString = testErrBuffer.toString(UTF8) assertTrue(TAG in logString) assertTrue(MESSAGE in logString) @@ -132,7 +132,7 @@ class ConsoleLoggerTests { @Test fun checkAssertWithoutThrowable() { - ConsoleLogger.assert(TAG, MESSAGE, null, Metadata()) + ConsoleLogger.assert(TAG, MESSAGE, Metadata(), null) val logString = testErrBuffer.toString(UTF8) assertTrue(TAG in logString) assertTrue(MESSAGE in logString) @@ -141,7 +141,7 @@ class ConsoleLoggerTests { @Test fun checkAssertWithThrowable() { val throwable = Throwable() - ConsoleLogger.assert(TAG, MESSAGE, throwable, Metadata()) + ConsoleLogger.assert(TAG, MESSAGE, Metadata(), throwable) val logString = testErrBuffer.toString(UTF8) assertTrue(TAG in logString) assertTrue(MESSAGE in logString) diff --git a/logging/src/macosX64Main/kotlin/ConsoleLogger.kt b/logging/src/macosX64Main/kotlin/ConsoleLogger.kt index 95d2fad2..e088971e 100644 --- a/logging/src/macosX64Main/kotlin/ConsoleLogger.kt +++ b/logging/src/macosX64Main/kotlin/ConsoleLogger.kt @@ -32,27 +32,27 @@ public actual object ConsoleLogger : Logger { fflush(stream) } - override fun verbose(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { + override fun verbose(tag: String, message: String, metadata: ReadMetadata, throwable: Throwable?) { print(stdout, "V", tag, message, throwable) } - override fun debug(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { + override fun debug(tag: String, message: String, metadata: ReadMetadata, throwable: Throwable?) { print(stdout, "D", tag, message, throwable) } - override fun info(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { + override fun info(tag: String, message: String, metadata: ReadMetadata, throwable: Throwable?) { print(stdout, "I", tag, message, throwable) } - override fun warn(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { + override fun warn(tag: String, message: String, metadata: ReadMetadata, throwable: Throwable?) { print(stdout, "W", tag, message, throwable) } - override fun error(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { + override fun error(tag: String, message: String, metadata: ReadMetadata, throwable: Throwable?) { print(stderr, "E", tag, message, throwable) } - override fun assert(tag: String, message: String, throwable: Throwable?, metadata: ReadMetadata) { + override fun assert(tag: String, message: String, metadata: ReadMetadata, throwable: Throwable?) { print(stderr, "A", tag, message, throwable) } } From 04319f013eaa2dde0f1f5ba1114aea050e526147 Mon Sep 17 00:00:00 2001 From: Cedrick Cooke Date: Wed, 14 Apr 2021 14:39:45 -0700 Subject: [PATCH 3/3] Micro-optimizations around atomics/locking --- logging/src/commonMain/kotlin/DispatchLogger.kt | 4 ++-- logging/src/commonMain/kotlin/Pool.kt | 9 ++++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/logging/src/commonMain/kotlin/DispatchLogger.kt b/logging/src/commonMain/kotlin/DispatchLogger.kt index 58519210..8ca64c74 100644 --- a/logging/src/commonMain/kotlin/DispatchLogger.kt +++ b/logging/src/commonMain/kotlin/DispatchLogger.kt @@ -1,7 +1,7 @@ package com.juul.tuulbox.logging import kotlinx.atomicfu.atomic -import kotlinx.atomicfu.getAndUpdate +import kotlinx.atomicfu.update /** Implementation of [Logger] which dispatches calls to consumer [Logger]s. */ public class DispatchLogger : Logger { @@ -13,7 +13,7 @@ public class DispatchLogger : Logger { /** Add a consumer to receive future dispatch calls. */ public fun install(consumer: Logger) { - consumers.getAndUpdate { it + consumer } + consumers.update { it + consumer } } /** Uninstall all installed consumers. */ diff --git a/logging/src/commonMain/kotlin/Pool.kt b/logging/src/commonMain/kotlin/Pool.kt index 33a59435..a2dca10b 100644 --- a/logging/src/commonMain/kotlin/Pool.kt +++ b/logging/src/commonMain/kotlin/Pool.kt @@ -6,11 +6,14 @@ import kotlinx.atomicfu.locks.withLock /** While a [Pool] is logically thread safe, Kotlin/Native's memory model requires @ThreadLocal on instances of this. */ internal class Pool( private val factory: () -> T, - private val refurbish: (T) -> Unit + private val refurbish: (T) -> Unit, ) { private val lock = reentrantLock() private val cache = ArrayDeque() - fun borrow(): T = lock.withLock { cache.removeLastOrNull() ?: factory() } - fun recycle(value: T) = lock.withLock { cache.addLast(value.apply(refurbish)) } + fun borrow(): T = lock.withLock { cache.removeLastOrNull() } ?: factory() + fun recycle(value: T) { + refurbish(value) + lock.withLock { cache.addLast(value) } + } }