mirror of
https://github.com/mii443/prometheus-android-exporter.git
synced 2025-08-22 23:25:40 +00:00
remote write UI
This commit is contained in:
@ -14,8 +14,8 @@ private const val TAG: String = "CONFIGURATION"
|
|||||||
//TODO register within prometheus foundation
|
//TODO register within prometheus foundation
|
||||||
private const val defaultPrometheusServerPort: Int = 10101
|
private const val defaultPrometheusServerPort: Int = 10101
|
||||||
private const val defaultRemoteWriteScrapeInterval: Int = 30 // seconds
|
private const val defaultRemoteWriteScrapeInterval: Int = 30 // seconds
|
||||||
private const val defaultRemoteWriteMaxSamplesPerSend : Int = 60 // seconds
|
private const val defaultRemoteWriteMaxSamplesPerExport : Int = 60 // seconds
|
||||||
private const val defaultRemoteWriteSendInterval : Int = 120 // seconds
|
private const val defaultRemoteWriteExportInterval : Int = 120 // seconds
|
||||||
|
|
||||||
// serialization classes for parsing YAML configuration file
|
// serialization classes for parsing YAML configuration file
|
||||||
@Serializable
|
@Serializable
|
||||||
@ -35,8 +35,8 @@ data class PromConfigFile(
|
|||||||
remoteWriteEndpoint = this.remote_write?.remote_write_endpoint ?: "",
|
remoteWriteEndpoint = this.remote_write?.remote_write_endpoint ?: "",
|
||||||
prometheusServerEnabled = this.prometheus_server?.enabled ?: true,
|
prometheusServerEnabled = this.prometheus_server?.enabled ?: true,
|
||||||
prometheusServerPort = this.prometheus_server?.port ?: defaultPrometheusServerPort,
|
prometheusServerPort = this.prometheus_server?.port ?: defaultPrometheusServerPort,
|
||||||
remoteWriteMaxSamplesPerSend = this.remote_write?.max_samples_per_send ?: defaultRemoteWriteMaxSamplesPerSend,
|
remoteWriteMaxSamplesPerExport = this.remote_write?.max_samples_per_export ?: defaultRemoteWriteMaxSamplesPerExport,
|
||||||
remoteWriteSendInterval = this.remote_write?.send_interval ?: defaultRemoteWriteSendInterval,
|
remoteWriteExportInterval = this.remote_write?.export_interval ?: defaultRemoteWriteExportInterval,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -59,8 +59,8 @@ data class RemoteWriteConfigFile(
|
|||||||
val enabled: Boolean?,
|
val enabled: Boolean?,
|
||||||
val scrape_interval: Int?,
|
val scrape_interval: Int?,
|
||||||
val remote_write_endpoint: String?,
|
val remote_write_endpoint: String?,
|
||||||
val max_samples_per_send: Int?,
|
val max_samples_per_export: Int?,
|
||||||
val send_interval: Int?,
|
val export_interval: Int?,
|
||||||
)
|
)
|
||||||
|
|
||||||
// configuration of a work manager worker
|
// configuration of a work manager worker
|
||||||
@ -75,8 +75,8 @@ data class PromConfiguration(
|
|||||||
val remoteWriteEnabled: Boolean = false,
|
val remoteWriteEnabled: Boolean = false,
|
||||||
val remoteWriteScrapeInterval: Int = defaultRemoteWriteScrapeInterval,
|
val remoteWriteScrapeInterval: Int = defaultRemoteWriteScrapeInterval,
|
||||||
val remoteWriteEndpoint: String = "",
|
val remoteWriteEndpoint: String = "",
|
||||||
val remoteWriteSendInterval : Int = 60,
|
val remoteWriteExportInterval : Int = defaultRemoteWriteExportInterval,
|
||||||
val remoteWriteMaxSamplesPerSend : Int = 500,
|
val remoteWriteMaxSamplesPerExport : Int = defaultRemoteWriteMaxSamplesPerExport,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun toStructuredText(): String {
|
fun toStructuredText(): String {
|
||||||
@ -91,8 +91,8 @@ data class PromConfiguration(
|
|||||||
remote_write:
|
remote_write:
|
||||||
enabled: $remoteWriteEnabled
|
enabled: $remoteWriteEnabled
|
||||||
scrape_interval: $remoteWriteScrapeInterval
|
scrape_interval: $remoteWriteScrapeInterval
|
||||||
send_interval: $remoteWriteSendInterval
|
export_interval: $remoteWriteExportInterval
|
||||||
max_samples_per_send: $remoteWriteMaxSamplesPerSend
|
max_samples_per_export: $remoteWriteMaxSamplesPerExport
|
||||||
remote_write_endpoint: "$remoteWriteEndpoint"
|
remote_write_endpoint: "$remoteWriteEndpoint"
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.height
|
|||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
import androidx.compose.material.AlertDialog
|
import androidx.compose.material.AlertDialog
|
||||||
import androidx.compose.material.Button
|
import androidx.compose.material.Button
|
||||||
import androidx.compose.material.ButtonDefaults
|
import androidx.compose.material.ButtonDefaults
|
||||||
@ -34,6 +35,7 @@ import androidx.compose.runtime.remember
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.text.input.KeyboardType
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.navigation.NavHostController
|
import androidx.navigation.NavHostController
|
||||||
@ -84,7 +86,7 @@ fun HomePage(
|
|||||||
|
|
||||||
ConfigFileState.SUCCESS -> ConfigFileSuccessPage(promViewModel = promViewModel)
|
ConfigFileState.SUCCESS -> ConfigFileSuccessPage(promViewModel = promViewModel)
|
||||||
ConfigFileState.LOADING -> LoadingPage(Modifier)
|
ConfigFileState.LOADING -> LoadingPage(Modifier)
|
||||||
ConfigFileState.MISSING -> TabPage(promViewModel, navController)
|
ConfigFileState.MISSING -> TabPage(promViewModel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,7 +176,6 @@ private fun StartStopButton(
|
|||||||
@Composable
|
@Composable
|
||||||
private fun TabPage(
|
private fun TabPage(
|
||||||
promViewModel: PromViewModel,
|
promViewModel: PromViewModel,
|
||||||
navController: NavHostController,
|
|
||||||
) {
|
) {
|
||||||
val tabs = mapOf(0 to "Prom Server", 1 to "PushProx", 2 to "Remote write")
|
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()
|
||||||
@ -188,7 +189,7 @@ private fun TabPage(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
when (uiState.tabIndex) {
|
when (uiState.tabIndex) {
|
||||||
0 -> PrometheusServerPage(promViewModel, Modifier)
|
0 -> PrometheusServerPage(promViewModel)
|
||||||
1 -> PushProxPage(promViewModel)
|
1 -> PushProxPage(promViewModel)
|
||||||
2 -> RemoteWritePage(promViewModel)
|
2 -> RemoteWritePage(promViewModel)
|
||||||
}
|
}
|
||||||
@ -198,7 +199,6 @@ private fun TabPage(
|
|||||||
@Composable
|
@Composable
|
||||||
private fun PrometheusServerPage(
|
private fun PrometheusServerPage(
|
||||||
promViewModel: PromViewModel,
|
promViewModel: PromViewModel,
|
||||||
modifier: Modifier
|
|
||||||
) {
|
) {
|
||||||
val uiState: PromUiState by promViewModel.uiState.collectAsState()
|
val uiState: PromUiState by promViewModel.uiState.collectAsState()
|
||||||
|
|
||||||
@ -300,6 +300,7 @@ private fun PushProxPage(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO implement this
|
||||||
@Composable
|
@Composable
|
||||||
private fun RemoteWritePage(
|
private fun RemoteWritePage(
|
||||||
promViewModel: PromViewModel,
|
promViewModel: PromViewModel,
|
||||||
@ -307,10 +308,72 @@ private fun RemoteWritePage(
|
|||||||
val uiState: PromUiState by promViewModel.uiState.collectAsState()
|
val uiState: PromUiState by promViewModel.uiState.collectAsState()
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier,
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
) {
|
) {
|
||||||
//TODO implement this
|
Text("Remote write configuration:")
|
||||||
Text("Remote write configuration")
|
|
||||||
|
TextField(
|
||||||
|
value = uiState.promConfig.remoteWriteEndpoint,
|
||||||
|
singleLine = true,
|
||||||
|
onValueChange = {
|
||||||
|
promViewModel.updatePromConfig(UpdatePromConfig.PushproxFqdn, it)
|
||||||
|
},
|
||||||
|
label = {
|
||||||
|
Text(text = "Remote write endpoint")
|
||||||
|
},
|
||||||
|
modifier = Modifier.padding(bottom = 12.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
TextField(
|
||||||
|
value = uiState.promConfig.remoteWriteScrapeInterval.toString(),
|
||||||
|
singleLine = true,
|
||||||
|
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
|
||||||
|
onValueChange = {
|
||||||
|
promViewModel.updatePromConfig(UpdatePromConfig.RemoteWriteScrapeInterval, it.toInt())
|
||||||
|
},
|
||||||
|
label = {
|
||||||
|
Text(text = "Scrape interval in seconds")
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
TextField(
|
||||||
|
value = uiState.promConfig.remoteWriteMaxSamplesPerExport.toString(),
|
||||||
|
singleLine = true,
|
||||||
|
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
|
||||||
|
onValueChange = {
|
||||||
|
promViewModel.updatePromConfig(
|
||||||
|
UpdatePromConfig.RemoteWriteMaxSamplesPerExport,
|
||||||
|
it.toInt(),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
label = {
|
||||||
|
Text(text = "Max number of samples per export")
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
TextField(
|
||||||
|
value = uiState.promConfig.remoteWriteExportInterval.toString(),
|
||||||
|
singleLine = true,
|
||||||
|
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
|
||||||
|
onValueChange = {
|
||||||
|
promViewModel.updatePromConfig(UpdatePromConfig.PushproxProxyUrl, it.toInt())
|
||||||
|
},
|
||||||
|
label = {
|
||||||
|
Text(text = "Export interval in seconds")
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
Switch(
|
||||||
|
checked = uiState.promConfig.remoteWriteEnabled,
|
||||||
|
onCheckedChange = { value: Boolean? ->
|
||||||
|
if (value != null) {
|
||||||
|
promViewModel.updatePromConfig(UpdatePromConfig.RemoteWriteEnabled, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@ import android.util.Log
|
|||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
|
||||||
import androidx.work.Constraints
|
import androidx.work.Constraints
|
||||||
import androidx.work.Data
|
import androidx.work.Data
|
||||||
import androidx.work.ExistingWorkPolicy
|
import androidx.work.ExistingWorkPolicy
|
||||||
@ -20,7 +19,6 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
|||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import java.util.UUID
|
|
||||||
|
|
||||||
private val TAG: String = "PROMVIEWMODEL"
|
private val TAG: String = "PROMVIEWMODEL"
|
||||||
|
|
||||||
@ -40,6 +38,8 @@ enum class UpdatePromConfig {
|
|||||||
RemoteWriteEnabled,
|
RemoteWriteEnabled,
|
||||||
RemoteWriteScrapeInterval,
|
RemoteWriteScrapeInterval,
|
||||||
RemoteWriteEndpoint,
|
RemoteWriteEndpoint,
|
||||||
|
RemoteWriteexportInterval,
|
||||||
|
RemoteWriteMaxSamplesPerExport,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class ExporterState {
|
enum class ExporterState {
|
||||||
@ -57,7 +57,6 @@ data class PromUiState(
|
|||||||
val configValidationException: String? = null,
|
val configValidationException: String? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class PromViewModel() : ViewModel() {
|
class PromViewModel() : ViewModel() {
|
||||||
|
|
||||||
private val _uiState = MutableStateFlow(PromUiState())
|
private val _uiState = MutableStateFlow(PromUiState())
|
||||||
@ -338,6 +337,22 @@ class PromViewModel() : ViewModel() {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UpdatePromConfig.RemoteWriteexportInterval -> _uiState.update {current ->
|
||||||
|
current.copy(
|
||||||
|
promConfig = current.promConfig.copy(
|
||||||
|
remoteWriteExportInterval = value as Int
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdatePromConfig.RemoteWriteMaxSamplesPerExport -> _uiState.update { current ->
|
||||||
|
current.copy(
|
||||||
|
promConfig = current.promConfig.copy(
|
||||||
|
remoteWriteMaxSamplesPerExport = value as Int
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package com.birdthedeveloper.prometheus.android.prometheus.android.exporter.work
|
|||||||
|
|
||||||
import android.app.NotificationManager
|
import android.app.NotificationManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.Log
|
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.work.CoroutineWorker
|
import androidx.work.CoroutineWorker
|
||||||
import androidx.work.ForegroundInfo
|
import androidx.work.ForegroundInfo
|
||||||
@ -60,8 +59,8 @@ class PromWorker(
|
|||||||
scrapeInterval = config.remoteWriteScrapeInterval,
|
scrapeInterval = config.remoteWriteScrapeInterval,
|
||||||
remoteWriteEndpoint = config.remoteWriteEndpoint,
|
remoteWriteEndpoint = config.remoteWriteEndpoint,
|
||||||
collectorRegistry = collectorRegistry,
|
collectorRegistry = collectorRegistry,
|
||||||
sendInterval = config.remoteWriteSendInterval,
|
exportInterval = config.remoteWriteExportInterval,
|
||||||
maxSamplesPerSend = config.remoteWriteMaxSamplesPerSend,
|
maxSamplesPerExport = config.remoteWriteMaxSamplesPerExport,
|
||||||
) { context }
|
) { context }
|
||||||
)
|
)
|
||||||
launch {
|
launch {
|
||||||
|
@ -68,8 +68,8 @@ data class RemoteWriteConfiguration(
|
|||||||
val scrapeInterval: Int,
|
val scrapeInterval: Int,
|
||||||
val remoteWriteEndpoint: String,
|
val remoteWriteEndpoint: String,
|
||||||
val collectorRegistry: CollectorRegistry,
|
val collectorRegistry: CollectorRegistry,
|
||||||
val maxSamplesPerSend: Int,
|
val maxSamplesPerExport: Int,
|
||||||
val sendInterval : Int,
|
val exportInterval : Int,
|
||||||
val getContext : () -> Context,
|
val getContext : () -> Context,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -107,7 +107,7 @@ class RemoteWriteSender(private val config: RemoteWriteConfiguration) {
|
|||||||
private suspend fun sendAll(){
|
private suspend fun sendAll(){
|
||||||
scrapesAreBeingSent = true
|
scrapesAreBeingSent = true
|
||||||
while (!storage.isEmpty()){
|
while (!storage.isEmpty()){
|
||||||
val body = storage.getScrapedSamplesCompressedProtobuf(config.maxSamplesPerSend)
|
val body = storage.getScrapedSamplesCompressedProtobuf(config.maxSamplesPerExport)
|
||||||
ExponentialBackoff.runWithBackoff( {sendRequestToRemoteWrite(body)}, {}, false)
|
ExponentialBackoff.runWithBackoff( {sendRequestToRemoteWrite(body)}, {}, false)
|
||||||
}
|
}
|
||||||
lastTimeRemoteWriteSent = System.currentTimeMillis()
|
lastTimeRemoteWriteSent = System.currentTimeMillis()
|
||||||
@ -128,7 +128,7 @@ class RemoteWriteSender(private val config: RemoteWriteConfiguration) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun timeHasPassed() : Boolean {
|
private fun timeHasPassed() : Boolean {
|
||||||
return lastTimeRemoteWriteSent < System.currentTimeMillis() - config.sendInterval * 1000
|
return lastTimeRemoteWriteSent < System.currentTimeMillis() - config.exportInterval * 1000
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun conditionsForRemoteWrite() : Boolean {
|
private fun conditionsForRemoteWrite() : Boolean {
|
||||||
@ -136,7 +136,7 @@ class RemoteWriteSender(private val config: RemoteWriteConfiguration) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun enoughSamplesScraped() : Boolean {
|
private fun enoughSamplesScraped() : Boolean {
|
||||||
return storage.getLength() > config.maxSamplesPerSend
|
return storage.getLength() > config.maxSamplesPerExport
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun senderManager(channel : Channel<Unit>){
|
private suspend fun senderManager(channel : Channel<Unit>){
|
||||||
|
@ -36,6 +36,6 @@ remote_write:
|
|||||||
remote_write_endpoint:
|
remote_write_endpoint:
|
||||||
|
|
||||||
# default value is 500 scrapes
|
# default value is 500 scrapes
|
||||||
max_samples_per_send: 500
|
max_samples_per_export: 500
|
||||||
|
|
||||||
send_interval: 60 # default
|
export_interval: 60 # default
|
||||||
|
Reference in New Issue
Block a user