diff --git a/client/.idea/deploymentTargetDropDown.xml b/client/.idea/deploymentTargetDropDown.xml index 3fb2dab..1acd161 100644 --- a/client/.idea/deploymentTargetDropDown.xml +++ b/client/.idea/deploymentTargetDropDown.xml @@ -7,11 +7,11 @@ - + - + \ No newline at end of file diff --git a/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/compose/Configuration.kt b/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/compose/Configuration.kt index af287cb..0605434 100644 --- a/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/compose/Configuration.kt +++ b/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/compose/Configuration.kt @@ -17,6 +17,8 @@ private const val defaultPrometheusServerPort: Int = 10101 private const val defaultRemoteWriteScrapeInterval: Int = 30 // seconds private const val defaultRemoteWriteMaxSamplesPerExport: Int = 60 // seconds private const val defaultRemoteWriteExportInterval: Int = 120 // seconds +private const val defaultRemoteWriteJobLabel: String = "test job" +private const val defaultRemoteWriteInstanceLabel: String = "test instance" // serialization classes for parsing YAML configuration file @Serializable @@ -41,6 +43,8 @@ data class PromConfigFile( ?: defaultRemoteWriteMaxSamplesPerExport).toString(), remoteWriteExportInterval = (this.remote_write?.export_interval ?: defaultRemoteWriteExportInterval).toString(), + remoteWriteInstanceLabel = this.remote_write?.instance ?: defaultRemoteWriteInstanceLabel, + remoteWriteJobLabel = this.remote_write?.job ?: defaultRemoteWriteJobLabel, ) } } @@ -65,6 +69,8 @@ data class RemoteWriteConfigFile( val remote_write_endpoint: String? = null, val max_samples_per_export: Int? = null, val export_interval: Int? = null, + val job: String? = null, + val instance: String? = null, ) // configuration of a work manager worker @@ -81,6 +87,8 @@ data class PromConfiguration( val remoteWriteEndpoint: String = "", val remoteWriteExportInterval: String = defaultRemoteWriteExportInterval.toString(), val remoteWriteMaxSamplesPerExport: String = defaultRemoteWriteMaxSamplesPerExport.toString(), + val remoteWriteInstanceLabel: String = defaultRemoteWriteInstanceLabel, + val remoteWriteJobLabel: String = defaultRemoteWriteJobLabel, ) { fun toStructuredText(): String { @@ -98,6 +106,8 @@ data class PromConfiguration( export_interval: $remoteWriteExportInterval max_samples_per_export: $remoteWriteMaxSamplesPerExport remote_write_endpoint: "$remoteWriteEndpoint" + instance: "$remoteWriteInstanceLabel" + job: "$remoteWriteJobLabel" """.trimIndent() } diff --git a/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/compose/HomeActivity.kt b/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/compose/HomeActivity.kt index 00b2231..f0dbdcc 100644 --- a/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/compose/HomeActivity.kt +++ b/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/compose/HomeActivity.kt @@ -335,10 +335,10 @@ private fun RemoteWritePage( ) TextField( - value = uiState.promConfig.remoteWriteMaxSamplesPerExport, + value = uiState.promConfig.remoteWriteInstanceLabel, singleLine = true, onValueChange = { - promViewModel.updatePromConfig(UpdatePromConfig.RemoteWriteMaxSamplesPerExport, it) + promViewModel.updatePromConfig(UpdatePromConfig.RemoteWriteInstanceLabel, it) }, label = { Text(text = "Target label instance") @@ -347,10 +347,10 @@ private fun RemoteWritePage( ) TextField( - value = uiState.promConfig.remoteWriteExportInterval, + value = uiState.promConfig.remoteWriteJobLabel, singleLine = true, onValueChange = { - promViewModel.updatePromConfig(UpdatePromConfig.RemoteWriteExportInterval, it) + promViewModel.updatePromConfig(UpdatePromConfig.RemoteWriteJobLabel, it) }, label = { Text(text = "Target label job") diff --git a/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/compose/PromViewModel.kt b/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/compose/PromViewModel.kt index 9efd146..43e6e66 100644 --- a/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/compose/PromViewModel.kt +++ b/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/compose/PromViewModel.kt @@ -42,6 +42,8 @@ enum class UpdatePromConfig { RemoteWriteEndpoint, RemoteWriteExportInterval, RemoteWriteMaxSamplesPerExport, + RemoteWriteJobLabel, + RemoteWriteInstanceLabel, } enum class ExporterState { @@ -388,6 +390,23 @@ class PromViewModel : ViewModel() { ) ) } + + UpdatePromConfig.RemoteWriteInstanceLabel -> _uiState.update {current -> + current.copy( + promConfig = current.promConfig.copy( + remoteWriteInstanceLabel = value as String + ) + ) + } + + UpdatePromConfig.RemoteWriteJobLabel -> _uiState.update {current -> + current.copy( + promConfig = current.promConfig.copy( + remoteWriteJobLabel = value as String + ) + ) + } + } } } diff --git a/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/worker/PromWorker.kt b/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/worker/PromWorker.kt index e83428e..f8786de 100644 --- a/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/worker/PromWorker.kt +++ b/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/worker/PromWorker.kt @@ -74,6 +74,10 @@ class PromWorker( collectorRegistry = collectorRegistry, exportInterval = config.remoteWriteExportInterval.toInt(), maxSamplesPerExport = config.remoteWriteMaxSamplesPerExport.toInt(), + targetLabels = mapOf( + "job" to config.remoteWriteJobLabel, + "instance" to config.remoteWriteInstanceLabel, + ), ) { context } ) launch { diff --git a/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/worker/PushProxClient.kt b/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/worker/PushProxClient.kt index 170484e..9ce722f 100644 --- a/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/worker/PushProxClient.kt +++ b/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/worker/PushProxClient.kt @@ -142,6 +142,7 @@ class PushProxClient(private val pushProxConfig: PushProxConfig) { Log.d(TAG, "Polling finished") } else { Log.d(TAG, "Skipping poll because network not available") + throw Exception("Device is not connected to any network") } } @@ -177,24 +178,30 @@ class PushProxClient(private val pushProxConfig: PushProxConfig) { } // push metrics to pushprox - try { - val scrapeId: String = getIdFromResponseBody(pollResponseBody) - val pushRequestBody: String = composeRequestBody(scrapedMetrics, scrapeId) + // only try to push metrics if device is connected to the network + if (Util.deviceIsConnectedToInternet(context.getContext())){ + try { + val scrapeId: String = getIdFromResponseBody(pollResponseBody) + val pushRequestBody: String = composeRequestBody(scrapedMetrics, scrapeId) - context.client.request(context.pushUrl) { - method = HttpMethod.Post - setBody(pushRequestBody) - } - - - pushProxConfig.countSuccessfulScrape() - } catch (e: Exception) { - if (e is CancellationException) { - throw e + context.client.request(context.pushUrl) { + method = HttpMethod.Post + setBody(pushRequestBody) + } + + + pushProxConfig.countSuccessfulScrape() + } catch (e: Exception) { + if (e is CancellationException) { + throw e + } + counters.pushError() + Log.v(TAG, "Push exception $e") + return } + }else{ counters.pushError() - Log.v(TAG, "Push exception $e") - return + Log.d(TAG, "device is not connected to any network") } } diff --git a/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/worker/RemoteWriteSender.kt b/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/worker/RemoteWriteSender.kt index 24f1ff7..5e33dc3 100644 --- a/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/worker/RemoteWriteSender.kt +++ b/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/worker/RemoteWriteSender.kt @@ -81,12 +81,13 @@ data class RemoteWriteConfiguration( val collectorRegistry: CollectorRegistry, val maxSamplesPerExport: Int, val exportInterval: Int, + val targetLabels: Map, val getContext: () -> Context, ) class RemoteWriteSender(private val config: RemoteWriteConfiguration) { private val lastTimeRingBuffer = LastTimeRingBuffer(config.scrapeInterval) - private val storage: RemoteWriteSenderStorage = RemoteWriteSenderSimpleMemoryStorage() + private val storage: RemoteWriteSenderStorage = RemoteWriteSenderSimpleMemoryStorage(config.targetLabels) private var scrapesAreBeingSent: Boolean = false private lateinit var client: HttpClient private var lastTimeRemoteWriteSent: Long = 0 @@ -228,33 +229,40 @@ class RemoteWriteSender(private val config: RemoteWriteConfiguration) { private suspend fun sendRequestToRemoteWrite(body: ByteArray, numOfMetricScrapes: Int) { Log.d(TAG, "Exporting remote write to prometheus now") - val response = client.post(config.remoteWriteEndpoint) { - setBody(body) - headers { - append(HttpHeaders.ContentEncoding, "snappy") - append(HttpHeaders.ContentType, "application/protobuf") - append(HttpHeaders.UserAgent, "Prometheus Android Exporter") - header("X-Prometheus-Remote-Write-Version", "0.1.0") - } - } - Log.d(TAG, "Response status: ${response.status}") - - when (response.status) { - HttpStatusCode.NoContent -> { - // this export was successful - storage.removeNumberOfScrapedSamples(numOfMetricScrapes) + // only send the request if device is online, otherwise throw exception + // ExponentialBackoff will catch the exception + if (Util.deviceIsConnectedToInternet(config.getContext())){ + val response = client.post(config.remoteWriteEndpoint) { + setBody(body) + headers { + append(HttpHeaders.ContentEncoding, "snappy") + append(HttpHeaders.ContentType, "application/protobuf") + append(HttpHeaders.UserAgent, "Prometheus Android Exporter") + header("X-Prometheus-Remote-Write-Version", "0.1.0") + } } - HttpStatusCode.BadRequest -> { - // probably some error or race condition has occured - // give up trying to send this data - storage.removeNumberOfScrapedSamples(numOfMetricScrapes) - } + Log.d(TAG, "Response status: ${response.status}") - else -> { - throw TryExportMetricsAgainException("Status code: ${response.status.description}") + when (response.status) { + HttpStatusCode.NoContent -> { + // this export was successful + storage.removeNumberOfScrapedSamples(numOfMetricScrapes) + } + + HttpStatusCode.BadRequest -> { + // probably some error or race condition has occured + // give up trying to send this data + storage.removeNumberOfScrapedSamples(numOfMetricScrapes) + } + + else -> { + throw TryExportMetricsAgainException("Status code: ${response.status.description}") + } } + }else{ + throw TryExportMetricsAgainException("Device is not connected to any network") } } } diff --git a/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/worker/RemoteWriteSenderMemStorage.kt b/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/worker/RemoteWriteSenderMemStorage.kt index c24958b..3837ffa 100644 --- a/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/worker/RemoteWriteSenderMemStorage.kt +++ b/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/worker/RemoteWriteSenderMemStorage.kt @@ -12,7 +12,7 @@ private typealias ConverterHashMap = HashMap, MutableList< private const val TAG: String = "REMOTE_WRITE_SENDER_MEMORY_SIMPLE_STORAGE" -class RemoteWriteSenderSimpleMemoryStorage : RemoteWriteSenderStorage() { +class RemoteWriteSenderSimpleMemoryStorage(val targetLabels: Map) : RemoteWriteSenderStorage() { private val data: Queue = LinkedList() private fun filterExpiredMetrics(metrics: MutableList) { @@ -107,6 +107,17 @@ class RemoteWriteSenderSimpleMemoryStorage : RemoteWriteSenderStorage() { return hashmapToProtobufWriteRequest(hashmap) } + private fun addTargetLabels(labels: MutableList){ + targetLabels.forEach { + val label = TimeSeriesLabel( + value = it.value, + name = it.key, + ) + + labels.add(label) + } + } + private fun processStorageTimeSeries(hashMap: ConverterHashMap, timeSeries: StorageTimeSeries) { // add remote write label to labels @@ -114,6 +125,7 @@ class RemoteWriteSenderSimpleMemoryStorage : RemoteWriteSenderStorage() { // and those scraped by Remote Write val labels: MutableList = timeSeries.labels.toMutableList() labels.add(remoteWriteLabel) + addTargetLabels(labels) val immutableLabels: List = labels.toList() if (hashMap[immutableLabels] == null) { diff --git a/config_file_structure.yaml b/config_file_structure.yaml index 83dca41..109ee96 100644 --- a/config_file_structure.yaml +++ b/config_file_structure.yaml @@ -42,7 +42,7 @@ remote_write: export_interval: 60 # default - # instance and job target labels, no defaults are provided + # instance and job target labels, defaults are provided # string values - instance: - job: + instance: "test instance" + job: "test job"