mirror of
https://github.com/mii443/prometheus-android-exporter.git
synced 2025-12-03 11:08:21 +00:00
update prom config function in view model
This commit is contained in:
@@ -47,6 +47,7 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'androidx.work:work-multiprocess:2.8.1'
|
||||
def core_version = "1.10.1"
|
||||
|
||||
// custom - prometheus client java library
|
||||
|
||||
@@ -5,7 +5,6 @@ import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
@@ -99,19 +98,19 @@ private fun TabPage(
|
||||
navController: NavHostController,
|
||||
modifier: Modifier,
|
||||
|
||||
){
|
||||
) {
|
||||
val tabs = mapOf(0 to "Prom Server", 1 to "PushProx", 2 to "Remote write")
|
||||
val uiState : PromUiState by promViewModel.uiState.collectAsState()
|
||||
val uiState: PromUiState by promViewModel.uiState.collectAsState()
|
||||
|
||||
Column(modifier = modifier) {
|
||||
TabRow(selectedTabIndex = uiState.tabIndex) {
|
||||
tabs.forEach{ (index, text) ->
|
||||
Tab(text = {Text(text)},
|
||||
tabs.forEach { (index, text) ->
|
||||
Tab(text = { Text(text) },
|
||||
selected = index == uiState.tabIndex,
|
||||
onClick = { promViewModel.updateTabIndex(index) })
|
||||
}
|
||||
}
|
||||
when(uiState.tabIndex){
|
||||
when (uiState.tabIndex) {
|
||||
0 -> PrometheusServerPage(promViewModel, Modifier)
|
||||
1 -> PushProxPage(promViewModel)
|
||||
2 -> RemoteWritePage(promViewModel)
|
||||
@@ -119,21 +118,6 @@ private fun TabPage(
|
||||
}
|
||||
}
|
||||
|
||||
private fun onCheckedChangeServer(
|
||||
value : Boolean,
|
||||
promViewModel: PromViewModel,
|
||||
showDialog : MutableState<String>
|
||||
){
|
||||
if (value) {
|
||||
val result : String? = promViewModel.turnServerOn()
|
||||
if(result != null){
|
||||
showDialog.value = result
|
||||
}
|
||||
} else {
|
||||
promViewModel.turnServerOff()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PrometheusServerPage(
|
||||
promViewModel: PromViewModel,
|
||||
@@ -149,12 +133,14 @@ private fun PrometheusServerPage(
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Text(text = "Turn on Android Exporter on default port ${promViewModel.getDefaultPort()}")
|
||||
Text(
|
||||
text = "Turn on Android Exporter on port ${uiState.promConfig.prometheusServerPort}"
|
||||
)
|
||||
Switch(
|
||||
checked = uiState.serverTurnedOn,
|
||||
checked = uiState.promConfig.prometheusServerEnabled,
|
||||
onCheckedChange = {value : Boolean? ->
|
||||
if(value != null){
|
||||
onCheckedChangeServer(value, promViewModel, showDialogText)
|
||||
promViewModel.updatePromConfig(UpdatePromConfig.prometheusServerEnabled, value)
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -197,22 +183,11 @@ private fun PushProxPage(
|
||||
modifier = Modifier.padding(bottom = 30.dp)
|
||||
)
|
||||
|
||||
if(uiState.pushProxTurnedOn){
|
||||
Text(
|
||||
text = """
|
||||
To edit PushProx proxy URL or FQDN, turn it off first.
|
||||
""".trimIndent(),
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.padding(bottom = 12.dp),
|
||||
)
|
||||
}
|
||||
|
||||
TextField(
|
||||
value = uiState.fqdn,
|
||||
value = uiState.promConfig.pushproxFqdn,
|
||||
singleLine = true,
|
||||
enabled = !uiState.pushProxTurnedOn,
|
||||
onValueChange = {
|
||||
promViewModel.updatePushProxFQDN(it)
|
||||
promViewModel.updatePromConfig(UpdatePromConfig.pushproxFqdn, it)
|
||||
},
|
||||
label = {
|
||||
Text(text = "Fully Qualified Domain Name")
|
||||
@@ -221,11 +196,10 @@ private fun PushProxPage(
|
||||
)
|
||||
|
||||
TextField(
|
||||
value = uiState.pushProxURL,
|
||||
value = uiState.promConfig.pushproxProxyUrl,
|
||||
singleLine = true,
|
||||
enabled = !uiState.pushProxTurnedOn,
|
||||
onValueChange = {
|
||||
promViewModel.updatePushProxURL(it)
|
||||
promViewModel.updatePromConfig(UpdatePromConfig.pushproxProxyUrl, it)
|
||||
},
|
||||
label = {
|
||||
Text(text = "PushProx proxy URL")
|
||||
|
||||
@@ -11,37 +11,41 @@ import androidx.work.NetworkType
|
||||
import androidx.work.OneTimeWorkRequestBuilder
|
||||
import androidx.work.OutOfQuotaPolicy
|
||||
import androidx.work.WorkManager
|
||||
import com.birdthedeveloper.prometheus.android.prometheus.android.exporter.worker.PushProxConfig
|
||||
import com.birdthedeveloper.prometheus.android.prometheus.android.exporter.worker.PushProxWorker
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import java.lang.Exception
|
||||
|
||||
enum class ConfigFileState {
|
||||
LOADING,
|
||||
ERROR, // file not found or was not parsed
|
||||
ERROR, // file was not parsed succesfully
|
||||
MISSING,
|
||||
SUCCESS
|
||||
}
|
||||
|
||||
enum class UpdatePromConfig {
|
||||
prometheusServerEnabled,
|
||||
prometheusServerPort,
|
||||
pushproxEnabled,
|
||||
pushproxFqdn,
|
||||
pushproxProxyUrl,
|
||||
remoteWriteEnabled,
|
||||
remoteWriteScrapeInterval,
|
||||
remoteWriteEndpoint,
|
||||
}
|
||||
|
||||
data class PromUiState(
|
||||
val tabIndex : Int = 0,
|
||||
val serverTurnedOn : Boolean = false,
|
||||
val pushProxTurnedOn : Boolean = false,
|
||||
val serverPort : Int? = null, // if null, use default port
|
||||
val fqdn : String = "test.example.com",
|
||||
val pushProxURL : String = "143.42.59.63:8080",
|
||||
val promConfig: PromConfiguration = PromConfiguration(),
|
||||
val configFileState : ConfigFileState = ConfigFileState.LOADING,
|
||||
)
|
||||
|
||||
private val TAG : String = "PROMVIEWMODEL"
|
||||
|
||||
class PromViewModel(): ViewModel() {
|
||||
// constants
|
||||
private val DEFAULT_SERVER_PORT : Int = 10101 //TODO register with prometheus community
|
||||
private val PROM_UNIQUE_WORK : String = "prom_unique_job"
|
||||
|
||||
|
||||
@@ -50,23 +54,44 @@ class PromViewModel(): ViewModel() {
|
||||
|
||||
private lateinit var getContext: () -> Context
|
||||
|
||||
|
||||
init {
|
||||
loadConfigurationFile()
|
||||
}
|
||||
|
||||
private fun loadConfigurationFile(){
|
||||
Log.v(TAG, "Checking for configuration file")
|
||||
viewModelScope.launch {
|
||||
//TODO check for configuration file
|
||||
delay(1000)
|
||||
_uiState.update { current ->
|
||||
current.copy(configFileState = ConfigFileState.MISSING)
|
||||
|
||||
val fileExists = PromConfiguration.configFileExists(context = getContext())
|
||||
if (fileExists) {
|
||||
val tempPromConfiguration : PromConfiguration
|
||||
try {
|
||||
tempPromConfiguration = PromConfiguration.loadFromConfigFile()
|
||||
|
||||
_uiState.update { current ->
|
||||
current.copy(
|
||||
promConfig = tempPromConfiguration,
|
||||
configFileState = ConfigFileState.SUCCESS,
|
||||
)
|
||||
}
|
||||
|
||||
}catch (e : Exception){
|
||||
_uiState.update { current ->
|
||||
current.copy(configFileState = ConfigFileState.ERROR)
|
||||
}
|
||||
}
|
||||
}else{
|
||||
_uiState.update { current ->
|
||||
current.copy(configFileState = ConfigFileState.MISSING)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getDefaultPort() : Int {
|
||||
return DEFAULT_SERVER_PORT
|
||||
}
|
||||
|
||||
fun initializeWithApplicationContext(getContext : () -> Context){
|
||||
this.getContext = getContext
|
||||
loadConfigurationFile()
|
||||
}
|
||||
|
||||
fun updateTabIndex(index : Int){
|
||||
@@ -77,59 +102,11 @@ class PromViewModel(): ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun getPromServerPort() : Int{
|
||||
return if(_uiState.value.serverPort != null){
|
||||
_uiState.value.serverPort!!
|
||||
}else{
|
||||
DEFAULT_SERVER_PORT
|
||||
}
|
||||
}
|
||||
|
||||
// if result is not null, it contains an error message
|
||||
fun turnServerOn() : String?{
|
||||
try{
|
||||
//TODO rewrite asap
|
||||
// prometheusServer.startInBackground(
|
||||
// PrometheusServerConfig(
|
||||
// getPromServerPort(),
|
||||
// ::performScrape
|
||||
// )
|
||||
// )
|
||||
}catch(e : Exception){
|
||||
Log.v(TAG, e.toString())
|
||||
return "Prometheus server failed!"
|
||||
}
|
||||
|
||||
_uiState.update { current ->
|
||||
current.copy(
|
||||
serverTurnedOn = true
|
||||
)
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
fun turnServerOff(){
|
||||
//TODO implement
|
||||
}
|
||||
|
||||
private fun validatePushProxSettings() : String? {
|
||||
val fqdn = _uiState.value.fqdn.trim().trim('\n')
|
||||
val url = _uiState.value.pushProxURL.trim().trim('\n')
|
||||
|
||||
if( fqdn.isEmpty() ) return "Fully Qualified Domain Name cannot be empty!"
|
||||
if( url.isEmpty() ) return "PushProx URL cannot be empty!"
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun launchPushProxUsingWorkManager(){
|
||||
fun startWorker(){
|
||||
val workManagerInstance = WorkManager.getInstance(getContext())
|
||||
|
||||
// worker configuration
|
||||
val inputData : Data = PushProxConfig(
|
||||
pushProxFqdn = _uiState.value.fqdn,
|
||||
pushProxUrl = _uiState.value.pushProxURL,
|
||||
).toData()
|
||||
val inputData : Data = _uiState.value.promConfig.toWorkData()
|
||||
|
||||
// constraints
|
||||
val constraints = Constraints.Builder()
|
||||
@@ -151,47 +128,54 @@ class PromViewModel(): ViewModel() {
|
||||
).enqueue()
|
||||
}
|
||||
|
||||
// if result is not null, it contains an error message
|
||||
fun turnPushProxOn() : String?{
|
||||
val error : String? = validatePushProxSettings()
|
||||
if(error != null){ return error }
|
||||
|
||||
// idempotent call
|
||||
launchPushProxUsingWorkManager()
|
||||
|
||||
_uiState.update { current ->
|
||||
current.copy(
|
||||
pushProxTurnedOn = true
|
||||
)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
fun turnPushProxOff(){
|
||||
fun stopWorker(){
|
||||
//TODO implement this thingy
|
||||
val workerManagerInstance = WorkManager.getInstance(getContext())
|
||||
workerManagerInstance.cancelUniqueWork(PROM_UNIQUE_WORK)
|
||||
|
||||
_uiState.update {current ->
|
||||
current.copy(
|
||||
pushProxTurnedOn = false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun updatePushProxURL(url : String){
|
||||
_uiState.update { current ->
|
||||
current.copy(
|
||||
pushProxURL = url
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun updatePushProxFQDN(fqdn : String){
|
||||
_uiState.update { current ->
|
||||
current.copy(
|
||||
fqdn = fqdn
|
||||
)
|
||||
fun updatePromConfig(part : UpdatePromConfig, value : Any){
|
||||
when(part){
|
||||
UpdatePromConfig.prometheusServerEnabled -> _uiState.update { current ->
|
||||
current.copy(promConfig = current.promConfig.copy(
|
||||
prometheusServerEnabled = value as Boolean
|
||||
))
|
||||
}
|
||||
UpdatePromConfig.prometheusServerPort -> _uiState.update { current ->
|
||||
current.copy(promConfig = current.promConfig.copy(
|
||||
prometheusServerPort = value as Int,
|
||||
))
|
||||
}
|
||||
UpdatePromConfig.pushproxEnabled -> _uiState.update { current ->
|
||||
current.copy(promConfig = current.promConfig.copy(
|
||||
pushproxEnabled = value as Boolean,
|
||||
))
|
||||
}
|
||||
UpdatePromConfig.pushproxFqdn -> _uiState.update { current ->
|
||||
current.copy(promConfig = current.promConfig.copy(
|
||||
pushproxFqdn = value as String,
|
||||
))
|
||||
}
|
||||
UpdatePromConfig.pushproxProxyUrl -> _uiState.update { current ->
|
||||
current.copy(promConfig = current.promConfig.copy(
|
||||
pushproxProxyUrl = value as String,
|
||||
))
|
||||
}
|
||||
UpdatePromConfig.remoteWriteEnabled -> _uiState.update { current ->
|
||||
current.copy(promConfig = current.promConfig.copy(
|
||||
remoteWriteEnabled = value as Boolean,
|
||||
))
|
||||
}
|
||||
UpdatePromConfig.remoteWriteScrapeInterval -> _uiState.update { current ->
|
||||
current.copy(promConfig = current.promConfig.copy(
|
||||
remoteWriteScrapeInterval = value as Int,
|
||||
))
|
||||
}
|
||||
UpdatePromConfig.remoteWriteEndpoint -> _uiState.update { current ->
|
||||
current.copy(promConfig = current.promConfig.copy(
|
||||
remoteWriteEndpoint = value as String,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.birdthedeveloper.prometheus.android.prometheus.android.exporter.compose
|
||||
|
||||
import android.content.Context
|
||||
import androidx.work.Data
|
||||
import androidx.work.workDataOf
|
||||
|
||||
@@ -11,16 +12,17 @@ data class PromConfiguration(
|
||||
val prometheusServerEnabled : Boolean = true,
|
||||
val prometheusServerPort : Int = defaultPrometheusServerPort,
|
||||
val pushproxEnabled : Boolean = false,
|
||||
val pushproxFqdn : String? = null,
|
||||
val pushproxProxyUrl : String? = null,
|
||||
val pushproxFqdn : String = "",
|
||||
val pushproxProxyUrl : String = "",
|
||||
val remoteWriteEnabled : Boolean = false,
|
||||
val remoteWriteScrapeInterval : Int = defaultRemoteWriteScrapeInterval,
|
||||
val remoteWriteEndpoint : String? = null,
|
||||
val remoteWriteEndpoint : String = "",
|
||||
) {
|
||||
private val filepath : String = ""
|
||||
private val filepath : String = "config.yaml"
|
||||
private val alternativeFilepath : String = "config.yml"
|
||||
|
||||
companion object {
|
||||
suspend fun configFileExists(): Boolean {
|
||||
suspend fun configFileExists(context : Context): Boolean {
|
||||
//TODO implement this asap
|
||||
return false
|
||||
}
|
||||
@@ -30,11 +32,11 @@ data class PromConfiguration(
|
||||
prometheusServerEnabled = data.getBoolean("0", true),
|
||||
prometheusServerPort = data.getInt("1", defaultPrometheusServerPort),
|
||||
pushproxEnabled = data.getBoolean("2", false),
|
||||
pushproxFqdn = data.getString("3"),
|
||||
pushproxProxyUrl = data.getString("4"),
|
||||
pushproxFqdn = data.getString("3") ?: "",
|
||||
pushproxProxyUrl = data.getString("4") ?: "",
|
||||
remoteWriteEnabled = data.getBoolean("5", false),
|
||||
remoteWriteScrapeInterval = data.getInt("6", defaultRemoteWriteScrapeInterval),
|
||||
remoteWriteEndpoint = data.getString("7"),
|
||||
remoteWriteEndpoint = data.getString("7") ?: "",
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.birdthedeveloper.prometheus.android.prometheus.android.exporter.worker
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import androidx.work.WorkerParameters
|
||||
import androidx.work.multiprocess.RemoteCoroutineWorker
|
||||
import com.birdthedeveloper.prometheus.android.prometheus.android.exporter.compose.PromConfiguration
|
||||
|
||||
private val TAG = "Worker"
|
||||
|
||||
class PromWorker(
|
||||
val context : Context,
|
||||
val parameters : WorkerParameters,
|
||||
) : RemoteCoroutineWorker(context = context, parameters = parameters) {
|
||||
|
||||
override suspend fun doRemoteWork(): Result {
|
||||
val inputConfiguration : PromConfiguration = PromConfiguration.fromWorkData(inputData)
|
||||
|
||||
while(true){
|
||||
Log.v(TAG, "Worker is working")
|
||||
}
|
||||
|
||||
//TODO implement this asap
|
||||
|
||||
return Result.success()
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user