From 0586918bc18e32ac08567785d2a0352400e9831d Mon Sep 17 00:00:00 2001 From: uniumuniu Date: Fri, 13 Oct 2023 14:19:55 +0200 Subject: [PATCH] Implement Logger.kt --- build.gradle.kts | 17 ++- .../kotlin/com/featurevisor/sdk/Logger.kt | 52 +++++++++ .../kotlin/com/featurevisor/sdk/LoggerTest.kt | 108 ++++++++++++++++++ 3 files changed, 176 insertions(+), 1 deletion(-) create mode 100644 src/main/kotlin/com/featurevisor/sdk/Logger.kt create mode 100644 src/test/kotlin/com/featurevisor/sdk/LoggerTest.kt diff --git a/build.gradle.kts b/build.gradle.kts index ddae965..60b3dc3 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -58,9 +58,9 @@ dependencies { api("org.apache.commons:commons-math3:3.6.1") // This dependency is used internally, and not exposed to consumers on their own compile classpath. - implementation("com.google.guava:guava:31.1-jre") implementation("net.swiftzer.semver:semver:1.3.0") implementation("com.goncalossilva:murmurhash:0.4.0") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0") } // Apply a specific Java toolchain to ease working on different environments. @@ -80,3 +80,18 @@ tasks.named("test") { showStandardStreams = true } } + +// TODO: Remove excludes when Instance.kt is ready +sourceSets { + main { + kotlin { + exclude("com/featurevisor/sdk/Instance.kt") + exclude("com/featurevisor/sdk/InstanceOptions.kt") + } + } + test { + kotlin { + exclude("com/featurevisor/sdk/InstanceTest.kt") + } + } +} diff --git a/src/main/kotlin/com/featurevisor/sdk/Logger.kt b/src/main/kotlin/com/featurevisor/sdk/Logger.kt new file mode 100644 index 0000000..34776c0 --- /dev/null +++ b/src/main/kotlin/com/featurevisor/sdk/Logger.kt @@ -0,0 +1,52 @@ +package com.featurevisor.sdk + +import com.featurevisor.sdk.LogLevel.* + +typealias LogMessage = String +typealias LogDetails = Map +typealias LogHandler = (level: LogLevel, message: LogMessage, details: LogDetails?) -> Unit + +enum class LogLevel(val value: String) { + ERROR("error"), + WARN("warn"), + INFO("info"), + DEBUG("debug") +} + +class Logger( + private var levels: List, + private val handle: LogHandler, +) { + + companion object { + private val defaultLogLevels: List = listOf(ERROR, WARN) + private val defaultLogHandler: LogHandler = { level, message, _ -> + println("[${level.value}] $message") + } + + fun createLogger(levels: List = defaultLogLevels, handle: LogHandler = defaultLogHandler): Logger = + Logger(levels, handle) + } + fun setLevels(levels: List) { + this.levels = levels + } + + fun debug(message: LogMessage, details: LogDetails? = null) = + log(DEBUG, message, details) + + fun info(message: LogMessage, details: LogDetails? = null) = + log(INFO, message, details) + + fun warn(message: LogMessage, details: LogDetails? = null) = + log(WARN, message, details) + + fun error(message: LogMessage, details: LogDetails? = null) = + log(ERROR, message, details) + + + private fun log(level: LogLevel, message: LogMessage, details: LogDetails? = null) { + if (level in levels) { + handle(level, message, details) + } + } +} diff --git a/src/test/kotlin/com/featurevisor/sdk/LoggerTest.kt b/src/test/kotlin/com/featurevisor/sdk/LoggerTest.kt new file mode 100644 index 0000000..75259d4 --- /dev/null +++ b/src/test/kotlin/com/featurevisor/sdk/LoggerTest.kt @@ -0,0 +1,108 @@ +package com.featurevisor.sdk + +import com.featurevisor.sdk.LogLevel.DEBUG +import com.featurevisor.sdk.LogLevel.ERROR +import com.featurevisor.sdk.LogLevel.INFO +import com.featurevisor.sdk.LogLevel.WARN +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import org.junit.jupiter.api.Test + +class LoggerTest { + + private val mockLogMessage = "test message" + private val mockLogDetails: Map = emptyMap() + private val mockLogHandler: LogHandler = mockk { + every { this@mockk(any(), any(), any()) } answers { nothing } + } + + private val systemUnderTest = Logger.createLogger( + handle = mockLogHandler, + ) + + @Test + fun `log DEBUG message when level DEBUG is set`() { + systemUnderTest.setLevels(listOf(DEBUG)) + + systemUnderTest.debug( + message = mockLogMessage, + details = mockLogDetails, + ) + + verify(exactly = 1) { + mockLogHandler(DEBUG, mockLogMessage, mockLogDetails) + } + } + + @Test + fun `log INFO message when level INFO is set`() { + systemUnderTest.setLevels(listOf(INFO)) + + systemUnderTest.info( + message = mockLogMessage, + details = mockLogDetails, + ) + + verify(exactly = 1) { + mockLogHandler(INFO, mockLogMessage, mockLogDetails) + } + } + + @Test + fun `log WARN message when level WARN is set`() { + systemUnderTest.setLevels(listOf(WARN)) + + systemUnderTest.warn( + message = mockLogMessage, + details = mockLogDetails, + ) + + verify(exactly = 1) { + mockLogHandler(WARN, mockLogMessage, mockLogDetails) + } + } + + @Test + fun `log ERROR message when level ERROR is set`() { + systemUnderTest.setLevels(listOf(ERROR)) + + systemUnderTest.error( + message = mockLogMessage, + details = mockLogDetails, + ) + + verify(exactly = 1) { + mockLogHandler(ERROR, mockLogMessage, mockLogDetails) + } + } + + @Test + fun `do not log any message when not set in log levels`() { + systemUnderTest.setLevels(listOf()) + + systemUnderTest.info( + message = mockLogMessage, + details = mockLogDetails, + ) + systemUnderTest.warn( + message = mockLogMessage, + details = mockLogDetails, + ) + systemUnderTest.debug( + message = mockLogMessage, + details = mockLogDetails, + ) + systemUnderTest.error( + message = mockLogMessage, + details = mockLogDetails, + ) + + verify(exactly = 0) { + mockLogHandler(INFO, any(), any()) + mockLogHandler(WARN, any(), any()) + mockLogHandler(DEBUG, any(), any()) + mockLogHandler(ERROR, any(), any()) + } + } +}