Skip to content

Commit 22ca967

Browse files
committed
feat: database logger
1 parent 5788184 commit 22ca967

File tree

6 files changed

+156
-25
lines changed

6 files changed

+156
-25
lines changed

logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/debug/ChangeProfilingUseCase.kt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
package com.wire.kalium.logic.feature.debug
1919

2020
import com.wire.kalium.logic.di.UserStorage
21+
import com.wire.kalium.persistence.db.DBProfile
2122

2223
class ChangeProfilingUseCase(
2324
private val userStorage: UserStorage,
@@ -26,7 +27,11 @@ class ChangeProfilingUseCase(
2627
* Changes the profiling of the database (cipher_profile) if the profile is specified and the database is encrypted
2728
* @param enabled true to enable profiling, false to disable
2829
*/
29-
operator fun invoke(enabled: Boolean) {
30-
userStorage.database.changeProfiling(enabled)
30+
suspend operator fun invoke(status: DBProfile) {
31+
userStorage.database.debugExtension.changeProfiling(status)
32+
}
33+
34+
suspend operator fun invoke(enabled: Boolean) {
35+
userStorage.database.debugExtension.changeProfiling(if (enabled) DBProfile.ON.Device else DBProfile.Off)
3136
}
3237
}

logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/debug/DebugScope.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ class DebugScope internal constructor(
9393
private val legalHoldHandler: LegalHoldHandler,
9494
private val notificationTokenRepository: NotificationTokenRepository,
9595
private val scope: CoroutineScope,
96-
userStorage: UserStorage,
96+
private val userStorage: UserStorage,
9797
logger: KaliumLogger,
9898
internal val dispatcher: KaliumDispatcher = KaliumDispatcherImpl,
9999
) {
@@ -227,5 +227,7 @@ class DebugScope internal constructor(
227227
notificationTokenRepository,
228228
)
229229

230-
val changeProfiling: ChangeProfilingUseCase = ChangeProfilingUseCase(userStorage)
230+
val changeProfiling: ChangeProfilingUseCase get() = ChangeProfilingUseCase(userStorage)
231+
232+
val observeDatabaseLoggerState get() = ObserveDatabaseLoggerStateUseCase(userStorage)
231233
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Wire
3+
* Copyright (C) 2025 Wire Swiss GmbH
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see http://www.gnu.org/licenses/.
17+
*/
18+
package com.wire.kalium.logic.feature.debug
19+
20+
import com.wire.kalium.logic.di.UserStorage
21+
import com.wire.kalium.persistence.db.DBProfile
22+
import kotlinx.coroutines.flow.Flow
23+
import kotlinx.coroutines.flow.map
24+
25+
class ObserveDatabaseLoggerStateUseCase(
26+
private val userStorage: UserStorage,
27+
) {
28+
suspend operator fun invoke(): Flow<Boolean> = userStorage.database.debugExtension.getProfilingState().map {
29+
it is DBProfile.ON
30+
}
31+
}

persistence/src/androidMain/kotlin/com/wire/kalium/persistence/db/UserDatabase.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ actual fun userDatabaseBuilder(
5757
dispatcher = dispatcher,
5858
platformDatabaseData = platformDatabaseData,
5959
isEncrypted = isEncryptionEnabled,
60-
cipherProfile = "logcat",
6160
)
6261
}
6362

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
* Wire
3+
* Copyright (C) 2025 Wire Swiss GmbH
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see http://www.gnu.org/licenses/.
17+
*/
18+
package com.wire.kalium.persistence.db
19+
20+
import app.cash.sqldelight.db.QueryResult
21+
import app.cash.sqldelight.db.SqlDriver
22+
import com.wire.kalium.persistence.dao.MetadataDAO
23+
import com.wire.kalium.persistence.kaliumLogger
24+
import kotlinx.coroutines.flow.Flow
25+
import kotlinx.coroutines.flow.map
26+
27+
class DebugExtension(
28+
private val sqlDriver: SqlDriver,
29+
private val isEncrypted: Boolean,
30+
private val metaDataDao: MetadataDAO,
31+
) {
32+
33+
suspend fun getProfilingState(): Flow<DBProfile?> =
34+
metaDataDao.valueByKeyFlow(KEY_CIPHER_PROFILE)
35+
.map {
36+
it?.let { DBProfile.fromString(it) }
37+
}
38+
39+
/**
40+
* Changes the profiling of the database (cipher_profile) if the profile is specified and the database is encrypted
41+
* @param enabled true to enable profiling, false to disable
42+
*/
43+
suspend fun changeProfiling(state: DBProfile): Long? =
44+
if (isEncrypted) {
45+
sqlDriver.executeQuery(
46+
identifier = null,
47+
sql = """PRAGMA cipher_profile= '${state.logTarget}';""",
48+
mapper = { cursor ->
49+
cursor.next()
50+
cursor.getLong(0).let { QueryResult.Value<Long?>(it) }
51+
},
52+
parameters = 0,
53+
).value.also {
54+
updateMetadata(state)
55+
}
56+
57+
} else {
58+
error("Cannot change profiling on unencrypted database")
59+
}
60+
61+
private suspend fun updateMetadata(state: DBProfile) {
62+
metaDataDao.insertValue(
63+
value = state.logTarget,
64+
key = KEY_CIPHER_PROFILE
65+
)
66+
}
67+
68+
private companion object {
69+
const val KEY_CIPHER_PROFILE = "cipher_profile"
70+
}
71+
}
72+
73+
sealed interface DBProfile {
74+
val logTarget: String
75+
76+
data object Off : DBProfile {
77+
override val logTarget: String = "off"
78+
79+
override fun toString(): String {
80+
return "off"
81+
}
82+
}
83+
84+
sealed interface ON : DBProfile {
85+
data object Device : ON {
86+
override val logTarget: String = "logcat"
87+
88+
override fun toString(): String {
89+
return "logcat"
90+
}
91+
}
92+
93+
data class CustomFile(override val logTarget: String) : ON {
94+
override fun toString(): String {
95+
return logTarget
96+
}
97+
}
98+
}
99+
100+
companion object {
101+
fun fromString(value: String): DBProfile = when (value) {
102+
"off" -> Off
103+
"logcat" -> ON.Device
104+
else -> ON.CustomFile(value)
105+
}
106+
}
107+
}

persistence/src/commonMain/kotlin/com/wire/kalium/persistence/db/UserDatabaseBuilder.kt

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,6 @@ class UserDatabaseBuilder internal constructor(
120120
private val platformDatabaseData: PlatformDatabaseData,
121121
private val isEncrypted: Boolean,
122122
private val queriesContext: CoroutineContext = KaliumDispatcherImpl.io,
123-
private val cipherProfile: String? = null,
124123
) {
125124

126125
internal val database: UserDatabase = UserDatabase(
@@ -314,30 +313,18 @@ class UserDatabaseBuilder internal constructor(
314313
queriesContext
315314
)
316315

316+
val debugExtension: DebugExtension
317+
get() = DebugExtension(
318+
sqlDriver = sqlDriver,
319+
metaDataDao = metadataDAO,
320+
isEncrypted = isEncrypted
321+
)
322+
317323
/**
318324
* @return the absolute path of the DB file or null if the DB file does not exist
319325
*/
320326
fun dbFileLocation(): String? = getDatabaseAbsoluteFileLocation(platformDatabaseData, userId)
321327

322-
/**
323-
* Changes the profiling of the database (cipher_profile) if the profile is specified and the database is encrypted
324-
* @param enabled true to enable profiling, false to disable
325-
*/
326-
fun changeProfiling(enabled: Boolean) {
327-
if (isEncrypted && cipherProfile != null) {
328-
val cipherProfileValue = if (enabled) cipherProfile else "off"
329-
sqlDriver.executeQuery(
330-
identifier = null,
331-
sql = "PRAGMA cipher_profile='$cipherProfileValue'",
332-
mapper = {
333-
it.next()
334-
it.getLong(0).let { QueryResult.Value<Long?>(it) }
335-
},
336-
parameters = 0,
337-
)
338-
}
339-
}
340-
341328
/**
342329
* drops DB connection and delete the DB file
343330
*/

0 commit comments

Comments
 (0)