Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/platform logger #33

Merged
merged 10 commits into from
Jul 29, 2024
17 changes: 17 additions & 0 deletions composeApp/src/androidMain/kotlin/AndroidLogger.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import android.util.Log
import org.noiseplanet.noisecapture.log.LogLevel
import org.noiseplanet.noisecapture.log.Logger

class AndroidLogger(
tag: String? = null,
) : Logger(tag) {

override fun display(level: LogLevel, message: String) {
when (level) {
LogLevel.DEBUG -> Log.d(tag, message)
LogLevel.INFO -> Log.i(tag, message)
LogLevel.WARNING -> Log.w(tag, message)
LogLevel.ERROR -> Log.e(tag, message)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,13 @@ import android.content.Context
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import org.koin.android.logger.AndroidLogger
import org.koin.core.logger.Logger
import org.koin.dsl.module

/**
* Android app entry point
*/
class MainActivity : ComponentActivity() {

private val androidLogger = AndroidLogger()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

Expand All @@ -26,9 +22,6 @@ class MainActivity : ComponentActivity() {
single<Context> { applicationContext }
single<Activity> { this@MainActivity }
},
module {
single<Logger> { androidLogger }
},
platformModule
)
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
package org.noiseplanet.noisecapture

import AndroidLogger

import org.koin.core.module.Module
import org.koin.dsl.module
import org.noiseplanet.noisecapture.audio.AndroidAudioSource
import org.noiseplanet.noisecapture.audio.AudioSource
import org.noiseplanet.noisecapture.log.Logger

/**
* Registers koin components specific to this platform
*/
val platformModule: Module = module {

factory<Logger> { params ->
val tag: String? = params.values.firstOrNull() as? String
AndroidLogger(tag)
}

factory<AudioSource> { AndroidAudioSource(logger = get()) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@ import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.consumeAsFlow
import org.koin.core.logger.Logger
import org.noiseplanet.noisecapture.log.Logger

/**
* Android audio source implementation
*
* @param logger Logger instance
*/
internal class AndroidAudioSource(private val logger: Logger) : AudioSource {
internal class AndroidAudioSource(
private val logger: Logger,
) : AudioSource {

private var audioThread: Thread? = null
private var audioRecorder: AudioRecorder? = null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import android.media.AudioRecord.ERROR_BAD_VALUE
import android.media.MediaRecorder
import android.os.Process
import kotlinx.coroutines.channels.Channel
import org.koin.core.logger.Logger
import org.noiseplanet.noisecapture.log.Logger
import java.util.concurrent.atomic.AtomicBoolean

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.noiseplanet.noisecapture.log

enum class LogLevel(val shortName: String) {
DEBUG("D"),
INFO("I"),
WARNING("W"),
ERROR("E")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package org.noiseplanet.noisecapture.log

/**
* Logger interface that should be implemented for each platform using native logging capabilities
*
* @param tag Tag that will be prefixed before each message logged by this instance.
* Should give context information about the caller (e.g. class name).
*/
abstract class Logger(
// TODO: Is there a way to infer class name at build time?
protected val tag: String? = null,
) {

/**
* Calls native logger implementation to display the given message from the given log level.
*
* Note: Log level is already written in the message, this property should just be used to
* determine which internal logger method should be called
*
* @param level: Log level
* @param message: Message to be displayed
*/
protected abstract fun display(level: LogLevel, message: String)

/**
* Logs a debug message.
*
* @param message Message to be displayed.
*/
fun debug(message: String) {
val level = LogLevel.DEBUG
display(
level,
message(level.shortName, message)
)
}

/**
* Logs an information message.
*
* @param message Message to be displayed.
*/
fun info(message: String) {
val level = LogLevel.INFO
display(
level,
message(level.shortName, message)
)
}

/**
* Logs a warning message.
*
* @param message Message to be displayed.
* @param throwable Optional throwable, if given the stack trace will be appended to the message.
*/
fun warning(message: String, throwable: Throwable? = null) {
val level = LogLevel.WARNING
display(
level,
message(level.shortName, message, throwable)
)
}

/**
* Logs an error message.
*
* @param message Message to be displayed.
* @param throwable Optional throwable, if given the stack trace will be appended to the message.
*/
fun error(message: String, throwable: Throwable? = null) {
val level = LogLevel.ERROR
display(
level,
message(level.shortName, message, throwable)
)
}

/**
* Formats the given message before logging.
*/
private fun message(
level: String,
msg: String,
t: Throwable? = null,
): String {
val str = if (tag != null) {
"[$tag] $level: $msg"
} else {
"$level: $msg"
}
return if (t == null) str else "$str $t"
}
}
14 changes: 7 additions & 7 deletions composeApp/src/iosMain/kotlin/MainViewController.kt
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import androidx.compose.runtime.Composable
import androidx.compose.ui.window.ComposeUIViewController
import org.koin.core.logger.PrintLogger
import org.noiseplanet.noisecapture.initKoin
import org.noiseplanet.noisecapture.platformModule

/**
* iOS application entry point
*/
@Composable
@Suppress("FunctionNaming")
fun MainViewController() = ComposeUIViewController {

// TODO: Platform specific implementation
val logger = PrintLogger()

initKoin().logger(logger)
initKoin(
additionalModules = listOf(
platformModule
)
)
App()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package org.noiseplanet.noisecapture

import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.ptr
import org.noiseplanet.noisecapture.log.LogLevel
import org.noiseplanet.noisecapture.log.Logger
import platform.darwin.OS_LOG_DEFAULT
import platform.darwin.OS_LOG_TYPE_DEFAULT
import platform.darwin.OS_LOG_TYPE_ERROR
import platform.darwin.OS_LOG_TYPE_FAULT
import platform.darwin.OS_LOG_TYPE_INFO
import platform.darwin.__dso_handle
import platform.darwin._os_log_internal

/**
* iOS Koin logger implementation that relies on native OSLog
*/
@OptIn(ExperimentalForeignApi::class)
class IOSLogger(
tag: String? = null,
) : Logger(tag) {

override fun display(level: LogLevel, message: String) {
when (level) {
LogLevel.DEBUG -> iosDebug(message)
LogLevel.INFO -> iosInfo(message)
LogLevel.WARNING -> iosWarn(message)
LogLevel.ERROR -> iosError(message)
else -> iosError(message)
}
}

private fun iosDebug(msg: String) {
_os_log_internal(
__dso_handle.ptr,
OS_LOG_DEFAULT,
OS_LOG_TYPE_INFO,
msg
)
}

private fun iosInfo(msg: String) {
_os_log_internal(
__dso_handle.ptr,
OS_LOG_DEFAULT,
OS_LOG_TYPE_DEFAULT,
msg
)
}

private fun iosWarn(msg: String) {
_os_log_internal(
__dso_handle.ptr,
OS_LOG_DEFAULT,
OS_LOG_TYPE_ERROR,
msg
)
}

private fun iosError(msg: String) {
_os_log_internal(
__dso_handle.ptr,
OS_LOG_DEFAULT,
OS_LOG_TYPE_FAULT,
msg
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.noiseplanet.noisecapture

import org.koin.core.module.Module
import org.koin.dsl.module
import org.noiseplanet.noisecapture.log.Logger

/**
* Registers koin components specific to this platform
*/
val platformModule: Module = module {

factory<Logger> { params ->
val tag: String? = params.values.firstOrNull() as? String
IOSLogger(tag)
}
}
11 changes: 4 additions & 7 deletions composeApp/src/wasmJsMain/kotlin/main.kt
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.window.ComposeViewport
import kotlinx.browser.document
import org.koin.core.logger.PrintLogger
import org.noiseplanet.noisecapture.initKoin
import org.noiseplanet.noisecapture.platformModule

@OptIn(ExperimentalComposeUiApi::class)
fun main() {

// TODO: Add a logger implementation that uses JS console
val logger = PrintLogger()

ComposeViewport(document.body!!) {
initKoin(
additionalModules = listOf(platformModule)
).logger(logger)

additionalModules = listOf(
platformModule
)
)
App()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.noiseplanet.noisecapture

import org.noiseplanet.noisecapture.interop.console
import org.noiseplanet.noisecapture.log.LogLevel
import org.noiseplanet.noisecapture.log.Logger


class JSLogger(
tag: String? = null,
) : Logger(tag) {

override fun display(level: LogLevel, message: String) {
when (level) {
LogLevel.DEBUG -> console.debug(message.toJsString())
LogLevel.INFO -> console.info(message.toJsString())
LogLevel.WARNING -> console.warn(message.toJsString())
LogLevel.ERROR -> console.error(message.toJsString())
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,14 @@ import org.koin.core.module.Module
import org.koin.dsl.module
import org.noiseplanet.noisecapture.audio.AudioSource
import org.noiseplanet.noisecapture.audio.JsAudioSource
import org.noiseplanet.noisecapture.log.Logger

val platformModule: Module = module {

factory<Logger> { params ->
val tag: String? = params.values.firstOrNull() as? String
JSLogger(tag)
}

factory<AudioSource> { JsAudioSource() }
}
Loading
Loading