mirror of
https://github.com/mii443/prometheus-android-exporter.git
synced 2025-08-22 15:15:35 +00:00
add job and instance target labels
This commit is contained in:
4
client/.idea/deploymentTargetDropDown.xml
generated
4
client/.idea/deploymentTargetDropDown.xml
generated
@ -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>
|
@ -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()
|
||||
}
|
||||
|
||||
|
@ -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")
|
||||
|
@ -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
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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"
|
||||
|
Reference in New Issue
Block a user