refactor(logging): use Timber instead of Kermit
Android-only project, so Timber (the de-facto Android logging lib) fits better than the KMP-oriented Kermit. - Catalog: kermit -> timber (com.jakewharton.timber:timber 5.0.1). - core:data: Ktor Logging bridged to Timber; safeCall logs via Timber. - app: plant Timber.DebugTree() in debug only (buildConfig enabled for BuildConfig.DEBUG).
This commit is contained in:
@@ -4,6 +4,13 @@ plugins {
|
|||||||
alias(libs.plugins.architecture.koin)
|
alias(libs.plugins.architecture.koin)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
// Needed for BuildConfig.DEBUG (gating the Timber DebugTree).
|
||||||
|
buildFeatures {
|
||||||
|
buildConfig = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
// :app is the only place modules are assembled and the dependency graph is wired.
|
// :app is the only place modules are assembled and the dependency graph is wired.
|
||||||
implementation(project(":core:data"))
|
implementation(project(":core:data"))
|
||||||
@@ -15,6 +22,8 @@ dependencies {
|
|||||||
implementation(libs.bundles.lifecycle.compose)
|
implementation(libs.bundles.lifecycle.compose)
|
||||||
// Material Components — required for the Material3 XML Activity theme.
|
// Material Components — required for the Material3 XML Activity theme.
|
||||||
implementation(libs.material)
|
implementation(libs.material)
|
||||||
|
// Logging — the DebugTree is planted here; other modules log via Timber's static API.
|
||||||
|
implementation(libs.timber)
|
||||||
|
|
||||||
androidTestImplementation(libs.androidx.compose.ui.test.junit4)
|
androidTestImplementation(libs.androidx.compose.ui.test.junit4)
|
||||||
debugImplementation(libs.androidx.compose.ui.test.manifest)
|
debugImplementation(libs.androidx.compose.ui.test.manifest)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import com.example.architecture.core.data.di.coreDataModule
|
|||||||
import org.koin.android.ext.koin.androidContext
|
import org.koin.android.ext.koin.androidContext
|
||||||
import org.koin.android.ext.koin.androidLogger
|
import org.koin.android.ext.koin.androidLogger
|
||||||
import org.koin.core.context.startKoin
|
import org.koin.core.context.startKoin
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Single Koin entry point. Feature modules append their own `*DataModule` / `*PresentationModule`
|
* Single Koin entry point. Feature modules append their own `*DataModule` / `*PresentationModule`
|
||||||
@@ -13,6 +14,12 @@ import org.koin.core.context.startKoin
|
|||||||
class ArchitectureApp : Application() {
|
class ArchitectureApp : Application() {
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
|
|
||||||
|
// Plant Timber only in debug; release builds get no logs (swap in a crash-reporting tree).
|
||||||
|
if (BuildConfig.DEBUG) {
|
||||||
|
Timber.plant(Timber.DebugTree())
|
||||||
|
}
|
||||||
|
|
||||||
startKoin {
|
startKoin {
|
||||||
androidLogger()
|
androidLogger()
|
||||||
androidContext(this@ArchitectureApp)
|
androidContext(this@ArchitectureApp)
|
||||||
|
|||||||
@@ -18,5 +18,5 @@ android {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(project(":core:domain"))
|
implementation(project(":core:domain"))
|
||||||
implementation(libs.kermit)
|
implementation(libs.timber)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ import io.ktor.client.request.setBody
|
|||||||
import io.ktor.client.request.url
|
import io.ktor.client.request.url
|
||||||
import io.ktor.client.statement.HttpResponse
|
import io.ktor.client.statement.HttpResponse
|
||||||
import kotlinx.serialization.SerializationException
|
import kotlinx.serialization.SerializationException
|
||||||
|
import timber.log.Timber
|
||||||
import java.net.UnknownHostException
|
import java.net.UnknownHostException
|
||||||
import java.nio.channels.UnresolvedAddressException
|
import java.nio.channels.UnresolvedAddressException
|
||||||
import kotlin.coroutines.cancellation.CancellationException
|
import kotlin.coroutines.cancellation.CancellationException
|
||||||
import co.touchlab.kermit.Logger as KermitLogger
|
|
||||||
|
|
||||||
suspend inline fun <reified Response : Any> HttpClient.get(
|
suspend inline fun <reified Response : Any> HttpClient.get(
|
||||||
route: String,
|
route: String,
|
||||||
@@ -65,17 +65,17 @@ suspend inline fun <reified T> safeCall(
|
|||||||
return try {
|
return try {
|
||||||
responseToResult(execute())
|
responseToResult(execute())
|
||||||
} catch (e: UnresolvedAddressException) {
|
} catch (e: UnresolvedAddressException) {
|
||||||
KermitLogger.withTag("HttpClient").e(e) { "No internet (unresolved address)" }
|
Timber.tag("HttpClient").e(e, "No internet (unresolved address)")
|
||||||
Result.Error(DataError.Network.NO_INTERNET)
|
Result.Error(DataError.Network.NO_INTERNET)
|
||||||
} catch (e: UnknownHostException) {
|
} catch (e: UnknownHostException) {
|
||||||
KermitLogger.withTag("HttpClient").e(e) { "No internet (unknown host)" }
|
Timber.tag("HttpClient").e(e, "No internet (unknown host)")
|
||||||
Result.Error(DataError.Network.NO_INTERNET)
|
Result.Error(DataError.Network.NO_INTERNET)
|
||||||
} catch (e: SerializationException) {
|
} catch (e: SerializationException) {
|
||||||
KermitLogger.withTag("HttpClient").e(e) { "Serialization failure" }
|
Timber.tag("HttpClient").e(e, "Serialization failure")
|
||||||
Result.Error(DataError.Network.SERIALIZATION)
|
Result.Error(DataError.Network.SERIALIZATION)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
if (e is CancellationException) throw e
|
if (e is CancellationException) throw e
|
||||||
KermitLogger.withTag("HttpClient").e(e) { "Unknown network failure" }
|
Timber.tag("HttpClient").e(e, "Unknown network failure")
|
||||||
Result.Error(DataError.Network.UNKNOWN)
|
Result.Error(DataError.Network.UNKNOWN)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,12 +10,13 @@ import io.ktor.http.ContentType
|
|||||||
import io.ktor.http.contentType
|
import io.ktor.http.contentType
|
||||||
import io.ktor.serialization.kotlinx.json.json
|
import io.ktor.serialization.kotlinx.json.json
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import co.touchlab.kermit.Logger as KermitLogger
|
import timber.log.Timber
|
||||||
import io.ktor.client.plugins.logging.Logger as KtorLogger
|
import io.ktor.client.plugins.logging.Logger as KtorLogger
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds the app's single [HttpClient]. The [engine] is injected so tests can pass a Ktor
|
* Builds the app's single [HttpClient]. The [engine] is injected so tests can pass a Ktor
|
||||||
* `MockEngine` while production passes OkHttp (see `coreDataModule`).
|
* `MockEngine` while production passes OkHttp (see `coreDataModule`). Ktor logging is bridged to
|
||||||
|
* Timber so all logs flow through one tree (planted in the Application).
|
||||||
*/
|
*/
|
||||||
object HttpClientFactory {
|
object HttpClientFactory {
|
||||||
fun create(engine: HttpClientEngine): HttpClient {
|
fun create(engine: HttpClientEngine): HttpClient {
|
||||||
@@ -30,7 +31,7 @@ object HttpClientFactory {
|
|||||||
install(Logging) {
|
install(Logging) {
|
||||||
logger = object : KtorLogger {
|
logger = object : KtorLogger {
|
||||||
override fun log(message: String) {
|
override fun log(message: String) {
|
||||||
KermitLogger.withTag("HttpClient").d(message)
|
Timber.tag("HttpClient").d(message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
level = LogLevel.ALL
|
level = LogLevel.ALL
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ ktor = "3.1.3"
|
|||||||
coil = "3.1.0"
|
coil = "3.1.0"
|
||||||
|
|
||||||
# Logging
|
# Logging
|
||||||
kermit = "2.0.5"
|
timber = "5.0.1"
|
||||||
|
|
||||||
# Material Components (Views renderer)
|
# Material Components (Views renderer)
|
||||||
material = "1.12.0"
|
material = "1.12.0"
|
||||||
@@ -110,7 +110,7 @@ coil-compose = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coil"
|
|||||||
coil-network-okhttp = { module = "io.coil-kt.coil3:coil-network-okhttp", version.ref = "coil" }
|
coil-network-okhttp = { module = "io.coil-kt.coil3:coil-network-okhttp", version.ref = "coil" }
|
||||||
|
|
||||||
# --- Logging ---
|
# --- Logging ---
|
||||||
kermit = { module = "co.touchlab:kermit", version.ref = "kermit" }
|
timber = { module = "com.jakewharton.timber:timber", version.ref = "timber" }
|
||||||
|
|
||||||
# --- Testing ---
|
# --- Testing ---
|
||||||
junit4 = { module = "junit:junit", version.ref = "junit4" }
|
junit4 = { module = "junit:junit", version.ref = "junit4" }
|
||||||
|
|||||||
Reference in New Issue
Block a user