add job and instance target labels

This commit is contained in:
Martin Ptáček
2023-07-29 21:12:08 +02:00
parent e9a5947e63
commit dffb10d748
9 changed files with 108 additions and 48 deletions

View File

@ -7,11 +7,11 @@
<deviceKey>
<Key>
<type value="VIRTUAL_DEVICE_PATH" />
<value value="$USER_HOME$/.android/avd/new3_device.avd" />
<value value="$USER_HOME$/.android/avd/new4_device.avd" />
</Key>
</deviceKey>
</Target>
</targetSelectedWithDropDown>
<timeTargetWasSelectedWithDropDown value="2023-07-27T06:47:49.277741303Z" />
<timeTargetWasSelectedWithDropDown value="2023-07-29T19:05:07.449016617Z" />
</component>
</project>

View File

@ -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()
}

View File

@ -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")

View File

@ -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
)
)
}
}
}
}

View File

@ -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 {

View File

@ -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")
}
}

View File

@ -81,12 +81,13 @@ data class RemoteWriteConfiguration(
val collectorRegistry: CollectorRegistry,
val maxSamplesPerExport: Int,
val exportInterval: Int,
val targetLabels: Map<String, String>,
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")
}
}
}

View File

@ -12,7 +12,7 @@ private typealias ConverterHashMap = HashMap<List<TimeSeriesLabel>, MutableList<
private const val TAG: String = "REMOTE_WRITE_SENDER_MEMORY_SIMPLE_STORAGE"
class RemoteWriteSenderSimpleMemoryStorage : RemoteWriteSenderStorage() {
class RemoteWriteSenderSimpleMemoryStorage(val targetLabels: Map<String, String>) : RemoteWriteSenderStorage() {
private val data: Queue<MetricsScrape> = LinkedList()
private fun filterExpiredMetrics(metrics: MutableList<MetricsScrape>) {
@ -107,6 +107,17 @@ class RemoteWriteSenderSimpleMemoryStorage : RemoteWriteSenderStorage() {
return hashmapToProtobufWriteRequest(hashmap)
}
private fun addTargetLabels(labels: MutableList<TimeSeriesLabel>){
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<TimeSeriesLabel> = timeSeries.labels.toMutableList()
labels.add(remoteWriteLabel)
addTargetLabels(labels)
val immutableLabels: List<TimeSeriesLabel> = labels.toList()
if (hashMap[immutableLabels] == null) {

View File

@ -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"