Repo created

This commit is contained in:
Fr4nz D13trich 2025-11-22 13:56:56 +01:00
parent 75dc487a7a
commit 39c29d175b
6317 changed files with 388324 additions and 2 deletions

View file

@ -0,0 +1,26 @@
plugins {
id(ThunderbirdPlugins.Library.kmp)
}
android {
namespace = "net.thunderbird.core.logging.legacy"
}
kotlin {
sourceSets {
androidMain.dependencies {
implementation(libs.timber)
implementation(projects.core.logging.implComposite)
implementation(projects.core.logging.implFile)
}
commonMain.dependencies {
api(projects.core.logging.api)
api(libs.androidx.annotation)
}
commonTest.dependencies {
implementation(projects.core.logging.testing)
}
}
}

View file

@ -0,0 +1,27 @@
package net.thunderbird.core.logging.legacy
import net.thunderbird.core.logging.composite.CompositeLogSink
import net.thunderbird.core.logging.file.FileLogSink
import timber.log.Timber
import timber.log.Timber.DebugTree
// TODO: Implementation https://github.com/thunderbird/thunderbird-android/issues/9573
class DebugLogConfigurator(
private val syncDebugCompositeSink: CompositeLogSink,
private val syncDebugFileLogSink: FileLogSink,
) {
fun updateLoggingStatus(isDebugLoggingEnabled: Boolean) {
Timber.uprootAll()
if (isDebugLoggingEnabled) {
Timber.plant(DebugTree())
}
}
fun updateSyncLogging(isSyncLoggingEnabled: Boolean) {
if (isSyncLoggingEnabled) {
syncDebugCompositeSink.manager.add(syncDebugFileLogSink)
} else {
syncDebugCompositeSink.manager.remove(syncDebugFileLogSink)
}
}
}

View file

@ -0,0 +1,159 @@
package net.thunderbird.core.logging.legacy
import androidx.annotation.Discouraged
import net.thunderbird.core.logging.LogMessage
import net.thunderbird.core.logging.LogTag
import net.thunderbird.core.logging.Logger
/**
* A static logging utility that implements [net.thunderbird.core.logging.Logger] and delegates to a [net.thunderbird.core.logging.Logger] implementation.
*
* You can initialize it in your application startup code, for example:
*
* ```kotlin
* import net.thunderbird.core.logging.Log
* import net.thunderbird.core.logging.DefaultLogger // or any other Logger implementation
* fun main() {
* val sink: LogSink = // Your LogSink implementation
* val logger: Logger = DefaultLogger(sink)
*
* Log.logger = logger
* Log.i("Application started")
* // Your application code here
* }
* ```
*/
@Discouraged(
message = "Use a net.thunderbird.core.logging.Logger instance via dependency injection instead. " +
"This class will be removed in a future release.",
)
object Log : Logger {
lateinit var logger: Logger
override fun verbose(
tag: LogTag?,
throwable: Throwable?,
message: () -> LogMessage,
) {
logger.verbose(
tag = tag,
throwable = throwable,
message = message,
)
}
override fun debug(
tag: LogTag?,
throwable: Throwable?,
message: () -> LogMessage,
) {
logger.debug(
tag = tag,
throwable = throwable,
message = message,
)
}
override fun info(
tag: LogTag?,
throwable: Throwable?,
message: () -> LogMessage,
) {
logger.info(
tag = tag,
throwable = throwable,
message = message,
)
}
override fun warn(
tag: LogTag?,
throwable: Throwable?,
message: () -> LogMessage,
) {
logger.warn(
tag = tag,
throwable = throwable,
message = message,
)
}
override fun error(
tag: LogTag?,
throwable: Throwable?,
message: () -> LogMessage,
) {
logger.error(
tag = tag,
throwable = throwable,
message = message,
)
}
// Legacy Logger implementation
@JvmStatic
fun v(message: String?, vararg args: Any?) {
logger.verbose(message = { formatMessage(message, args) })
}
@JvmStatic
fun v(t: Throwable?, message: String?, vararg args: Any?) {
logger.verbose(message = { formatMessage(message, args) }, throwable = t)
}
@JvmStatic
fun d(message: String?, vararg args: Any?) {
logger.debug(message = { formatMessage(message, args) })
}
@JvmStatic
fun d(t: Throwable?, message: String?, vararg args: Any?) {
logger.debug(message = { formatMessage(message, args) }, throwable = t)
}
@JvmStatic
fun i(message: String?, vararg args: Any?) {
logger.info(message = { formatMessage(message, args) })
}
@JvmStatic
fun i(t: Throwable?, message: String?, vararg args: Any?) {
logger.info(message = { formatMessage(message, args) }, throwable = t)
}
@JvmStatic
fun w(message: String?, vararg args: Any?) {
logger.warn(message = { formatMessage(message, args) })
}
@JvmStatic
fun w(t: Throwable?, message: String?, vararg args: Any?) {
logger.warn(message = { formatMessage(message, args) }, throwable = t)
}
@JvmStatic
fun e(message: String?, vararg args: Any?) {
logger.error(message = { formatMessage(message, args) })
}
@JvmStatic
fun e(t: Throwable?, message: String?, vararg args: Any?) {
logger.error(message = { formatMessage(message, args) }, throwable = t)
}
private fun formatMessage(message: String?, args: Array<out Any?>): String {
return if (message == null) {
""
} else if (args.isEmpty()) {
message
} else {
try {
String.format(message, *args)
} catch (e: Exception) {
"$message (Error formatting message: $e, args: ${args.joinToString()})"
}
}
}
}

View file

@ -0,0 +1,261 @@
package net.thunderbird.core.logging.legacy
import assertk.assertThat
import assertk.assertions.hasSize
import assertk.assertions.isEqualTo
import kotlin.test.Test
import net.thunderbird.core.logging.LogEvent
import net.thunderbird.core.logging.LogLevel
import net.thunderbird.core.logging.testing.TestLogger
import net.thunderbird.core.logging.testing.TestLogger.Companion.TIMESTAMP
class LogTest {
@Test
fun `init should set logger`() {
// Arrange
val logger = TestLogger()
// Act
Log.logger = logger
Log.info(
tag = "Test tag",
message = { "Test message" },
)
// Assert
assertThat(logger.events).hasSize(1)
assertThat(logger.events[0]).isEqualTo(
LogEvent(
level = LogLevel.INFO,
tag = "Test tag",
message = "Test message",
throwable = null,
timestamp = TIMESTAMP,
),
)
}
@Test
fun `log should add all event to the logger`() {
// Arrange
val logger = TestLogger()
val exceptionVerbose = Exception("Verbose exception")
val exceptionDebug = Exception("Debug exception")
val exceptionInfo = Exception("Info exception")
val exceptionWarn = Exception("Warn exception")
val exceptionError = Exception("Error exception")
Log.logger = logger
// Act
Log.verbose(
tag = "Verbose tag",
throwable = exceptionVerbose,
message = { "Verbose message" },
)
Log.debug(
tag = "Debug tag",
throwable = exceptionDebug,
message = { "Debug message" },
)
Log.info(
tag = "Info tag",
throwable = exceptionInfo,
message = { "Info message" },
)
Log.warn(
tag = "Warn tag",
throwable = exceptionWarn,
message = { "Warn message" },
)
Log.error(
tag = "Error tag",
throwable = exceptionError,
message = { "Error message" },
)
// Assert
val events = logger.events
assertThat(events).hasSize(5)
assertThat(events[0]).isEqualTo(
LogEvent(
level = LogLevel.VERBOSE,
tag = "Verbose tag",
message = "Verbose message",
throwable = exceptionVerbose,
timestamp = TIMESTAMP,
),
)
assertThat(events[1]).isEqualTo(
LogEvent(
level = LogLevel.DEBUG,
tag = "Debug tag",
message = "Debug message",
throwable = exceptionDebug,
timestamp = TIMESTAMP,
),
)
assertThat(events[2]).isEqualTo(
LogEvent(
level = LogLevel.INFO,
tag = "Info tag",
message = "Info message",
throwable = exceptionInfo,
timestamp = TIMESTAMP,
),
)
assertThat(events[3]).isEqualTo(
LogEvent(
level = LogLevel.WARN,
tag = "Warn tag",
message = "Warn message",
throwable = exceptionWarn,
timestamp = TIMESTAMP,
),
)
assertThat(events[4]).isEqualTo(
LogEvent(
level = LogLevel.ERROR,
tag = "Error tag",
message = "Error message",
throwable = exceptionError,
timestamp = TIMESTAMP,
),
)
}
@Test
fun `legacy methods should log correctly`() {
// Arrange
val logger = TestLogger()
val exception = Exception("Test exception")
Log.logger = logger
// Act - Test all legacy method signatures for each log level
// Verbose methods
Log.v("Verbose message %s", "arg1")
Log.v(exception, "Verbose message with exception %s", "arg1")
// Debug methods
Log.d("Debug message %s", "arg1")
Log.d(exception, "Debug message with exception %s", "arg1")
// Info methods
Log.i("Info message %s", "arg1")
Log.i(exception, "Info message with exception %s", "arg1")
// Warn methods
Log.w("Warn message %s", "arg1")
Log.w(exception, "Warn message with exception %s", "arg1")
// Error methods
Log.e("Error message %s", "arg1")
Log.e(exception, "Error message with exception %s", "arg1")
// Assert
val events = logger.events
assertThat(events).hasSize(10)
// Verify verbose events
assertThat(events[0]).isEqualTo(
LogEvent(
level = LogLevel.VERBOSE,
tag = null,
message = "Verbose message arg1",
throwable = null,
timestamp = TIMESTAMP,
),
)
assertThat(events[1]).isEqualTo(
LogEvent(
level = LogLevel.VERBOSE,
tag = null,
message = "Verbose message with exception arg1",
throwable = exception,
timestamp = TIMESTAMP,
),
)
// Verify debug events
assertThat(events[2]).isEqualTo(
LogEvent(
level = LogLevel.DEBUG,
tag = null,
message = "Debug message arg1",
throwable = null,
timestamp = TIMESTAMP,
),
)
assertThat(events[3]).isEqualTo(
LogEvent(
level = LogLevel.DEBUG,
tag = null,
message = "Debug message with exception arg1",
throwable = exception,
timestamp = TIMESTAMP,
),
)
// Verify info events
assertThat(events[4]).isEqualTo(
LogEvent(
level = LogLevel.INFO,
tag = null,
message = "Info message arg1",
throwable = null,
timestamp = TIMESTAMP,
),
)
assertThat(events[5]).isEqualTo(
LogEvent(
level = LogLevel.INFO,
tag = null,
message = "Info message with exception arg1",
throwable = exception,
timestamp = TIMESTAMP,
),
)
// Verify warn events
assertThat(events[6]).isEqualTo(
LogEvent(
level = LogLevel.WARN,
tag = null,
message = "Warn message arg1",
throwable = null,
timestamp = TIMESTAMP,
),
)
assertThat(events[7]).isEqualTo(
LogEvent(
level = LogLevel.WARN,
tag = null,
message = "Warn message with exception arg1",
throwable = exception,
timestamp = TIMESTAMP,
),
)
// Verify error events
assertThat(events[8]).isEqualTo(
LogEvent(
level = LogLevel.ERROR,
tag = null,
message = "Error message arg1",
throwable = null,
timestamp = TIMESTAMP,
),
)
assertThat(events[9]).isEqualTo(
LogEvent(
level = LogLevel.ERROR,
tag = null,
message = "Error message with exception arg1",
throwable = exception,
timestamp = TIMESTAMP,
),
)
}
}