remove pushprox worker

This commit is contained in:
Martin Ptáček
2023-05-31 13:37:28 +02:00
parent 15fe164855
commit eb9744373a
7 changed files with 106 additions and 144 deletions

3
.gitignore vendored
View File

@ -1 +1,4 @@
credentials/ credentials/
# configuration for working version of Android prometheus exporter
config.yaml

View File

@ -16,6 +16,17 @@ to run as ROOT. Exposes various hardware sensor metrics.
# Client # Client
## File configuration
Client application is configurable via a configuration file.
Place such file on your android device at a following path:
```
data/user/0/com.birdthedeveloper.prometheus.android.prometheus.android.exporter/files/
```
The name of such configuration file can be either `config.yaml` or `config.yml`
Configurable fields are described in `./config_file_structure.yaml`, all
fields are optional.
### ADB port forwarding ### ADB port forwarding
ADB port forwarding is usefull when running the client application ADB port forwarding is usefull when running the client application
on android emulator and prometheus database on the host on android emulator and prometheus database on the host

View File

@ -99,9 +99,15 @@ class PromViewModel(): ViewModel() {
when(_uiState.value.exporterState) { when(_uiState.value.exporterState) {
ExporterState.Running -> { ExporterState.Running -> {
stopWorker() stopWorker()
_uiState.update { current ->
current.copy(exporterState = ExporterState.NotRunning)
}
} }
ExporterState.NotRunning -> { ExporterState.NotRunning -> {
startWorker() startWorker()
_uiState.update { current ->
current.copy(exporterState = ExporterState.Running)
}
} }
} }
} }

View File

@ -4,13 +4,10 @@ import android.content.Context
import android.util.Log import android.util.Log
import androidx.work.Data import androidx.work.Data
import androidx.work.workDataOf import androidx.work.workDataOf
import com.birdthedeveloper.prometheus.android.prometheus.android.exporter.worker.PushProxConfig
import com.charleskorn.kaml.Yaml import com.charleskorn.kaml.Yaml
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import java.io.File import java.io.File
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlinx.serialization.decodeFromString
private const val TAG : String = "CONFIGURATION" private const val TAG : String = "CONFIGURATION"
@ -56,6 +53,7 @@ data class RemoteWriteConfigFile(
val remote_write_endpoint : String?, val remote_write_endpoint : String?,
) )
// configuration of a work manager worker
@Serializable @Serializable
data class PromConfiguration( data class PromConfiguration(
// the following are default values for various configuration settings // the following are default values for various configuration settings
@ -70,7 +68,6 @@ data class PromConfiguration(
) { ) {
fun toStructuredText() : String { fun toStructuredText() : String {
//TODO asap
return """ return """
prometheus_server: prometheus_server:
enabled: $prometheusServerEnabled enabled: $prometheusServerEnabled
@ -108,24 +105,22 @@ data class PromConfiguration(
val file = File(context.filesDir, filename) val file = File(context.filesDir, filename)
val alternativeFile = File(context.filesDir, alternativeFilename) val alternativeFile = File(context.filesDir, alternativeFilename)
val fileContents : String val fileContents : String = if (file.exists()){
if (file.exists()){ file.readText()
fileContents = file.readText()
}else if (alternativeFile.exists()){ }else if (alternativeFile.exists()){
fileContents = alternativeFile.readText() alternativeFile.readText()
}else{ }else{
throw Exception("configuration file does not exist!") throw Exception("configuration file does not exist!")
} }
val parsedYaml : PromConfigFile = Yaml.default.decodeFromString( val parsedConfig : PromConfigFile = Yaml.default.decodeFromString(
PromConfigFile.serializer(), PromConfigFile.serializer(),
fileContents fileContents
) )
Log.v(TAG, parsedYaml.prometheus_server?.port.toString()) Log.v(TAG, parsedConfig.prometheus_server?.port.toString())
return parsedConfig.toPromConfiguration()
return parsedYaml.toPromConfiguration()
} }
} }

View File

@ -1,37 +1,94 @@
package com.birdthedeveloper.prometheus.android.prometheus.android.exporter.worker package com.birdthedeveloper.prometheus.android.prometheus.android.exporter.worker
import android.app.NotificationManager
import android.content.Context import android.content.Context
import android.util.Log import androidx.core.app.NotificationCompat
import androidx.work.CoroutineWorker import androidx.work.CoroutineWorker
import androidx.work.ForegroundInfo
import androidx.work.WorkManager
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import com.birdthedeveloper.prometheus.android.prometheus.android.exporter.R
import com.birdthedeveloper.prometheus.android.prometheus.android.exporter.compose.PromConfiguration import com.birdthedeveloper.prometheus.android.prometheus.android.exporter.compose.PromConfiguration
import io.ktor.client.HttpClient import io.prometheus.client.CollectorRegistry
import io.ktor.client.engine.cio.CIO import io.prometheus.client.exporter.common.TextFormat
import io.ktor.client.statement.HttpResponse import java.io.StringWriter
import kotlinx.coroutines.delay
import java.time.LocalDateTime
import io.ktor.client.request.*
private val TAG = "Worker" private const val TAG = "Worker"
class PromWorker( class PromWorker(
context : Context, context : Context,
parameters : WorkerParameters, parameters : WorkerParameters,
) : CoroutineWorker(context, parameters) { ) : CoroutineWorker(context, parameters) {
private val collectorRegistry: CollectorRegistry = CollectorRegistry()
private val metricsEngine : MetricsEngine = MetricsEngine(context)
private val pushProxClient = PushProxClient(collectorRegistry, ::performScrape)
private lateinit var androidCustomExporter : AndroidCustomExporter
//TODO foreground notification
private val notificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as
NotificationManager
private fun performScrape() : String{
val writer = StringWriter()
TextFormat.write004(writer, collectorRegistry.metricFamilySamples())
return writer.toString()
}
private fun initializeWork(config : PromConfiguration){
// initialize metrics
androidCustomExporter = AndroidCustomExporter(metricsEngine).register(collectorRegistry)
}
private fun startServices(config : PromConfiguration){
if(config.prometheusServerEnabled){
//DO something
}
if(config.pushproxEnabled){
//DO something
}
if(config.remoteWriteEnabled){
//DO something
}
}
override suspend fun doWork(): Result { override suspend fun doWork(): Result {
val inputConfiguration : PromConfiguration = PromConfiguration.fromWorkData(inputData) val inputConfiguration : PromConfiguration = PromConfiguration.fromWorkData(inputData)
while(true){ // set foreground - //TODO is this right for the use case?
Log.v(TAG, "Worker is working " + LocalDateTime.now().toString()) setForeground(createForegroundInfo())
//TODO curl localhost
delay(1000L) initializeWork(inputConfiguration)
} startServices(inputConfiguration)
//TODO implement this asap //TODO implement this asap
return Result.success() return Result.success()
} }
//TODO foreground notification
private fun createForegroundInfo(): ForegroundInfo {
val id = "channel_id"
val title = "title"
val cancel = "cancel_download"
// This PendingIntent can be used to cancel the worker
val intent = WorkManager.getInstance(applicationContext)
.createCancelPendingIntent(getId())
val notification = NotificationCompat.Builder(applicationContext, id)
.setContentTitle(title)
.setTicker(title)
.setContentText("progress")
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setOngoing(true)
// Add the cancel action to the notification which can
// be used to cancel the worker
.addAction(android.R.drawable.ic_delete, cancel, intent)
.build()
return ForegroundInfo(1, notification)
}
} }

View File

@ -1,110 +0,0 @@
package com.birdthedeveloper.prometheus.android.prometheus.android.exporter.worker
import android.app.NotificationManager
import android.content.Context
import android.util.Log
import androidx.core.app.NotificationCompat
import androidx.work.CoroutineWorker
import androidx.work.ForegroundInfo
import androidx.work.WorkManager
import androidx.work.WorkerParameters
import com.birdthedeveloper.prometheus.android.prometheus.android.exporter.R
import io.prometheus.client.CollectorRegistry
import io.prometheus.client.exporter.common.TextFormat
import java.io.StringWriter
private val TAG = "PUSH_PROX_WORKER"
class PushProxWorker(
private val context : Context,
parameters : WorkerParameters
): CoroutineWorker(context, parameters){
private val notificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as
NotificationManager
override suspend fun doWork():Result {
//TODO implement this
val cache: PushProxWorkerCache = PushProxWorkerCache.getInstance {
return@getInstance context
}
setForeground(createForegroundInfo())
try{
val pushProxConfig : PushProxConfig = PushProxConfig.fromData(inputData)
cache.startBackground(pushProxConfig)
}catch(e : Exception){
Log.v(TAG, e.toString())
return Result.failure()
}
return Result.success()
}
private fun createForegroundInfo(): ForegroundInfo {
val id = "channel_id"
val title = "title"
val cancel = "cancel_download"
// This PendingIntent can be used to cancel the worker
val intent = WorkManager.getInstance(applicationContext)
.createCancelPendingIntent(getId())
val notification = NotificationCompat.Builder(applicationContext, id)
.setContentTitle(title)
.setTicker(title)
.setContentText("progress")
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setOngoing(true)
// Add the cancel action to the notification which can
// be used to cancel the worker
.addAction(android.R.drawable.ic_delete, cancel, intent)
.build()
return ForegroundInfo(1, notification)
}
}
// thread-safe singleton
class PushProxWorkerCache private constructor(
private val getContext: () -> Context
){
private val collectorRegistry: CollectorRegistry = CollectorRegistry()
private val metricsEngine : MetricsEngine = MetricsEngine(getContext())
private val pushProxClient = PushProxClient(collectorRegistry, ::performScrape)
private lateinit var androidCustomExporter : AndroidCustomExporter
init {
Log.v(TAG, "Initializing WorkerCache")
androidCustomExporter = AndroidCustomExporter(metricsEngine).register(collectorRegistry)
}
private fun performScrape() : String{
val writer = StringWriter()
TextFormat.write004(writer, collectorRegistry.metricFamilySamples())
return writer.toString()
}
suspend fun startBackground(pushProxConfig : PushProxConfig){
pushProxClient.startBackground(pushProxConfig)
}
companion object {
private var instance : PushProxWorkerCache? = null
fun getInstance(getContext: () -> Context) : PushProxWorkerCache {
if(instance == null){
synchronized(PushProxWorkerCache::class.java){
if (instance == null){
instance = PushProxWorkerCache(getContext)
}
}
}
return instance!!
}
}
}

View File

@ -3,18 +3,18 @@
# Settings specific to exporting metrics using a HTTP server # Settings specific to exporting metrics using a HTTP server
prometheus_server: prometheus_server:
enabled: false # default enabled: true # default
port: 22322 # default port: 10101 # default
# Settings specific to pushing metrics to pushprox proxy # Settings specific to pushing metrics to pushprox proxy
# This is handy for traversing network topologies such as NAT # This is handy for traversing network topologies such as NAT
pushprox: pushprox:
enabled: true # default enabled: false # default
# fully qualified domain name # fully qualified domain name
fqdn: "some-fqdn" # string, no default value provided fqdn: # string, no default value provided
proxy_url: "url" # string, no default value provided proxy_url: # string, no default value provided
# Settings specific to backfilling metrics using prometheus remote write # Settings specific to backfilling metrics using prometheus remote write
# #
@ -23,8 +23,8 @@ pushprox:
remote_write: remote_write:
# scrape interval in seconds # scrape interval in seconds
enabled: true # default enabled: false # default
scrape_interval: 60 # default scrape_interval: 30 # default
# where to post metrics # where to post metrics
remote_write_endpoint: "rem-wrirte" # string, no default value provided remote_write_endpoint: # string, no default value provided