Feat log db query (#471)

Co-authored-by: Florent Champigny <florent@bere.al>
This commit is contained in:
Florent CHAMPIGNY 2025-12-30 15:02:29 +01:00 committed by GitHub
parent 20b7b7b29c
commit 24bb623ebd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
48 changed files with 8659 additions and 129 deletions

View file

@ -19,6 +19,15 @@ fun floconRegisterDatabase(displayName: String, absolutePath: String) {
)
}
fun floconLogDatabaseQuery(dbName: String, sqlQuery: String, bindArgs: List<Any?>) {
FloconApp.instance?.client?.databasePlugin?.logQuery(
dbName = dbName,
sqlQuery = sqlQuery,
bindArgs = bindArgs,
)
}
interface FloconDatabasePlugin {
fun register(floconDatabaseModel: FloconDatabaseModel)
fun logQuery(dbName: String, sqlQuery: String, bindArgs: List<Any?>)
}

View file

@ -34,6 +34,7 @@ object Protocol {
object Method {
const val Query = "query"
const val GetDatabases = "getDatabases"
const val LogQuery = "logQuery"
}
}

View file

@ -13,6 +13,8 @@ import io.github.openflocon.flocon.plugins.database.model.fromdevice.QueryResult
import io.github.openflocon.flocon.plugins.database.model.fromdevice.listDeviceDataBaseDataModelToJson
import io.github.openflocon.flocon.plugins.database.model.fromdevice.toJson
import io.github.openflocon.flocon.plugins.database.model.todevice.DatabaseQueryMessage
import io.github.openflocon.flocon.plugins.database.model.fromdevice.DatabaseQueryLogModel
import io.github.openflocon.flocon.utils.currentTimeMillis
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.update
@ -94,4 +96,21 @@ internal class FloconDatabasePluginImpl(
registeredDatabases.update { it + floconDatabaseModel }
sendAllDatabases(sender)
}
override fun logQuery(dbName: String, sqlQuery: String, bindArgs: List<Any?>) {
try {
sender.send(
plugin = Protocol.FromDevice.Database.Plugin,
method = Protocol.FromDevice.Database.Method.LogQuery,
body = DatabaseQueryLogModel(
dbName = dbName,
sqlQuery = sqlQuery,
bindArgs = bindArgs.map { it.toString() },
timestamp = currentTimeMillis(),
).toJson(),
)
} catch (t: Throwable) {
FloconLogger.logError("Database logging error", t)
}
}
}

View file

@ -0,0 +1,23 @@
package io.github.openflocon.flocon.plugins.database.model.fromdevice
import io.github.openflocon.flocon.core.FloconEncoder
import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
@Serializable
internal data class DatabaseQueryLogModel(
val dbName: String,
val sqlQuery: String,
val bindArgs: List<String>?,
val timestamp: Long,
) {
fun toJson(): String {
return FloconEncoder.json.encodeToString<DatabaseQueryLogModel>(this)
}
companion object {
fun fromJson(json: String): DatabaseQueryLogModel {
return FloconEncoder.json.decodeFromString<DatabaseQueryLogModel>(json)
}
}
}

View file

@ -16,7 +16,9 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import io.github.openflocon.flocon.Flocon
import io.github.openflocon.flocon.FloconLogger
@ -24,6 +26,7 @@ import io.github.openflocon.flocon.myapplication.dashboard.initializeDashboard
import io.github.openflocon.flocon.myapplication.database.DogDatabase
import io.github.openflocon.flocon.myapplication.database.initializeDatabases
import io.github.openflocon.flocon.myapplication.database.initializeInMemoryDatabases
import io.github.openflocon.flocon.myapplication.database.model.DogEntity
import io.github.openflocon.flocon.myapplication.deeplinks.initializeDeeplinks
import io.github.openflocon.flocon.myapplication.graphql.GraphQlTester
import io.github.openflocon.flocon.myapplication.grpc.GrpcController
@ -95,6 +98,9 @@ class MainActivity : ComponentActivity() {
setContent {
MyApplicationTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
val scope = rememberCoroutineScope()
val context = LocalContext.current
Column(Modifier.fillMaxSize().padding(innerPadding)) {
FlowRow(
modifier = Modifier
@ -188,6 +194,23 @@ class MainActivity : ComponentActivity() {
) {
Text("send analytics event")
}
Button(
onClick = {
scope.launch {
DogDatabase.getDatabase(context).dogDao().insertDog(
DogEntity(
id = System.currentTimeMillis(),
name = "Flocon",
breed = "Golden Retriever ${System.currentTimeMillis()}",
age = 6,
pictureUrl = "https://picsum.photos/501/500.jpg",
)
)
}
}
) {
Text("Insert dog in DB")
}
}
ImagesListView(modifier = Modifier.fillMaxSize())

View file

@ -8,6 +8,8 @@ import io.github.openflocon.flocon.myapplication.database.dao.DogDao
import io.github.openflocon.flocon.myapplication.database.model.DogEntity
import io.github.openflocon.flocon.myapplication.database.model.HumanEntity
import io.github.openflocon.flocon.myapplication.database.model.HumanWithDogEntity
import io.github.openflocon.flocon.plugins.database.floconLogDatabaseQuery
import java.util.concurrent.Executors
@Database(
entities = [
@ -26,12 +28,17 @@ abstract class DogDatabase : RoomDatabase() {
private var INSTANCE: DogDatabase? = null
fun getDatabase(context: Context): DogDatabase {
val dbName = "dogs_database"
return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
DogDatabase::class.java,
"dogs_database" // Nom du fichier de la base de données Dogs
).fallbackToDestructiveMigration().build()
dbName
).setQueryCallback({ sqlQuery, bindArgs -> floconLogDatabaseQuery(
dbName = dbName, sqlQuery = sqlQuery, bindArgs = bindArgs
) }, Executors.newSingleThreadExecutor())
.fallbackToDestructiveMigration()
.build()
INSTANCE = instance
instance
}

View file

@ -2,20 +2,29 @@ package io.github.openflocon.flocon.myapplication.multi
import android.content.Context
import androidx.room.Room
import androidx.room.RoomDatabase
import io.github.openflocon.flocon.myapplication.multi.database.DogDatabase
import io.github.openflocon.flocon.myapplication.multi.database.FoodDatabase
import io.github.openflocon.flocon.plugins.database.floconLogDatabaseQuery
import java.util.concurrent.Executor
import java.util.concurrent.Executors
object Databases {
@Volatile
private var dogDatabase: DogDatabase? = null
fun getDogDatabase(context: Context): DogDatabase {
val dbName = "dogs_database"
return dogDatabase ?: synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
DogDatabase::class.java,
"dogs_database"
).fallbackToDestructiveMigration().build()
)
.setQueryCallback({ sqlQuery, bindArgs -> floconLogDatabaseQuery(
dbName = dbName, sqlQuery = sqlQuery, bindArgs = bindArgs
) }, Executors.newSingleThreadExecutor())
.fallbackToDestructiveMigration().build()
dogDatabase = instance
instance
}

View file

@ -12,10 +12,13 @@ import io.github.openflocon.flocon.myapplication.multi.Databases.getDogDatabase
import io.github.openflocon.flocon.myapplication.multi.Databases.getFoodDatabase
import io.github.openflocon.flocon.myapplication.multi.database.FoodDatabase
import io.github.openflocon.flocon.myapplication.multi.database.initializeDatabases
import io.github.openflocon.flocon.myapplication.multi.database.model.DogEntity
import io.github.openflocon.flocon.myapplication.multi.sharedpreferences.initializeSharedPreferences
import io.github.openflocon.flocon.myapplication.multi.ui.App
import io.ktor.client.HttpClient
import io.ktor.client.engine.okhttp.OkHttp
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
@ -43,8 +46,11 @@ class MainActivity : ComponentActivity() {
DummyHttpKtorCaller.initialize(ktorClient)
initializeSharedPreferences(applicationContext)
val dogDatabase = getDogDatabase(this)
initializeDatabases(
dogDatabase = getDogDatabase(this),
dogDatabase = dogDatabase,
foodDatabase = getFoodDatabase(this),
)

View file

@ -16,11 +16,14 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import io.github.openflocon.flocon.myapplication.multi.DummyHttpKtorCaller
import io.github.openflocon.flocon.myapplication.multi.dashboard.initializeDashboard
import io.github.openflocon.flocon.myapplication.multi.database.model.DogEntity
import io.github.openflocon.flocon.plugins.analytics.floconAnalytics
import io.github.openflocon.flocon.plugins.analytics.model.AnalyticsEvent
import io.github.openflocon.flocon.plugins.analytics.model.analyticsProperty
import io.github.openflocon.flocon.plugins.tables.floconTable
import io.github.openflocon.flocon.plugins.tables.model.toParam
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlin.random.Random
@Composable