This commit is contained in:
Martin Ptáček
2023-07-30 14:53:29 +02:00
parent 0ef86ed2d9
commit 3232b026df
10 changed files with 149 additions and 125 deletions

View File

@ -43,7 +43,8 @@ data class PromConfigFile(
?: defaultRemoteWriteMaxSamplesPerExport).toString(), ?: defaultRemoteWriteMaxSamplesPerExport).toString(),
remoteWriteExportInterval = (this.remote_write?.export_interval remoteWriteExportInterval = (this.remote_write?.export_interval
?: defaultRemoteWriteExportInterval).toString(), ?: defaultRemoteWriteExportInterval).toString(),
remoteWriteInstanceLabel = this.remote_write?.instance ?: defaultRemoteWriteInstanceLabel, remoteWriteInstanceLabel = this.remote_write?.instance
?: defaultRemoteWriteInstanceLabel,
remoteWriteJobLabel = this.remote_write?.job ?: defaultRemoteWriteJobLabel, remoteWriteJobLabel = this.remote_write?.job ?: defaultRemoteWriteJobLabel,
) )
} }
@ -112,7 +113,7 @@ data class PromConfiguration(
} }
companion object { companion object {
// data/user/0/com.birdthedeveloper.prometheus.android.exporter/files // data/user/0/com.birdthedeveloper.prometheus.android.exporter/files/
private const val filename: String = "config.yaml" private const val filename: String = "config.yaml"
private const val alternativeFilename: String = "config.yml" private const val alternativeFilename: String = "config.yml"
fun configFileExists(context: Context): Boolean { fun configFileExists(context: Context): Boolean {

View File

@ -252,6 +252,13 @@ class PromViewModel : ViewModel() {
"Scrape interval must be smaller than Export interval!" "Scrape interval must be smaller than Export interval!"
) )
} }
// check target labels
if (config.remoteWriteInstanceLabel.isEmpty() || config.remoteWriteJobLabel.isEmpty()) {
return displayConfigValidationDialog(
"Job target label and Instance target label must be set!"
)
}
} }
// validate settings for prometheus server // validate settings for prometheus server
@ -391,7 +398,7 @@ class PromViewModel : ViewModel() {
) )
} }
UpdatePromConfig.RemoteWriteInstanceLabel -> _uiState.update {current -> UpdatePromConfig.RemoteWriteInstanceLabel -> _uiState.update { current ->
current.copy( current.copy(
promConfig = current.promConfig.copy( promConfig = current.promConfig.copy(
remoteWriteInstanceLabel = value as String remoteWriteInstanceLabel = value as String
@ -399,7 +406,7 @@ class PromViewModel : ViewModel() {
) )
} }
UpdatePromConfig.RemoteWriteJobLabel -> _uiState.update {current -> UpdatePromConfig.RemoteWriteJobLabel -> _uiState.update { current ->
current.copy( current.copy(
promConfig = current.promConfig.copy( promConfig = current.promConfig.copy(
remoteWriteJobLabel = value as String remoteWriteJobLabel = value as String

View File

@ -38,8 +38,15 @@ fun SettingsPage(
} }
) )
Text( modifier = Modifier.padding(all = 20.dp), Text(
text = "This application is licensed under the Apache 2.0 license.", textAlign = TextAlign.Center,) modifier = Modifier.padding(all = 20.dp),
Text(modifier = Modifier.padding(all = 20.dp),text = "Author: Martin Ptacek, 2023", textAlign = TextAlign.Center,) text = "This application is licensed under the Apache 2.0 license.",
textAlign = TextAlign.Center,
)
Text(
modifier = Modifier.padding(all = 20.dp),
text = "Author: Martin Ptacek, 2023",
textAlign = TextAlign.Center,
)
} }
} }

View File

@ -2,10 +2,8 @@
package com.birdthedeveloper.prometheus.android.exporter.worker package com.birdthedeveloper.prometheus.android.exporter.worker
import android.os.CpuUsageInfo
import android.util.Log import android.util.Log
import io.prometheus.client.Collector import io.prometheus.client.Collector
import io.prometheus.client.Gauge
import io.prometheus.client.GaugeMetricFamily import io.prometheus.client.GaugeMetricFamily
private const val TAG = "ANDROID_EXPORTER" private const val TAG = "ANDROID_EXPORTER"
@ -34,7 +32,7 @@ class AndroidCustomExporter(private val metricEngine: MetricsEngine) : Collector
return mfs return mfs
} }
private fun collectBatteryChargeRatio(mfs : MutableList<MetricFamilySamples>){ private fun collectBatteryChargeRatio(mfs: MutableList<MetricFamilySamples>) {
val gauge = GaugeMetricFamily( val gauge = GaugeMetricFamily(
"android_battery_charge_ratio", "android_battery_charge_ratio",
"Current battery charge", "Current battery charge",
@ -44,7 +42,7 @@ class AndroidCustomExporter(private val metricEngine: MetricsEngine) : Collector
mfs.add(gauge) mfs.add(gauge)
} }
private fun collectUptimeInSeconds(mfs : MutableList<MetricFamilySamples>){ private fun collectUptimeInSeconds(mfs: MutableList<MetricFamilySamples>) {
val gauge = GaugeMetricFamily( val gauge = GaugeMetricFamily(
"android_uptime_seconds", "android_uptime_seconds",
"Android uptime in seconds", "Android uptime in seconds",
@ -54,11 +52,11 @@ class AndroidCustomExporter(private val metricEngine: MetricsEngine) : Collector
mfs.add(gauge) mfs.add(gauge)
} }
private fun collectHasWiFiConnection(mfs : MutableList<MetricFamilySamples>){ private fun collectHasWiFiConnection(mfs: MutableList<MetricFamilySamples>) {
metricEngine.getHasWiFiConnected()?.let { metricEngine.getHasWiFiConnected()?.let {
val result : Double = if (it) { val result: Double = if (it) {
1.0 1.0
}else{ } else {
0.0 0.0
} }
@ -72,10 +70,10 @@ class AndroidCustomExporter(private val metricEngine: MetricsEngine) : Collector
} }
} }
private fun collectBatteryIsCharging(mfs: MutableList<MetricFamilySamples>){ private fun collectBatteryIsCharging(mfs: MutableList<MetricFamilySamples>) {
val result = if (metricEngine.getBatteryIsCharging()){ val result = if (metricEngine.getBatteryIsCharging()) {
1.0 1.0
}else{ } else {
0.0 0.0
} }
@ -88,11 +86,11 @@ class AndroidCustomExporter(private val metricEngine: MetricsEngine) : Collector
mfs.add(gauge) mfs.add(gauge)
} }
private fun collectHasCellularConnection(mfs : MutableList<MetricFamilySamples>){ private fun collectHasCellularConnection(mfs: MutableList<MetricFamilySamples>) {
metricEngine.getHasCellularConnected()?.let { metricEngine.getHasCellularConnected()?.let {
val result : Double = if (it) { val result: Double = if (it) {
1.0 1.0
}else{ } else {
0.0 0.0
} }
@ -106,22 +104,24 @@ class AndroidCustomExporter(private val metricEngine: MetricsEngine) : Collector
} }
} }
private fun collectAndroidInfo(mfs : MutableList<MetricFamilySamples>){ private fun collectAndroidInfo(mfs: MutableList<MetricFamilySamples>) {
val gauge = GaugeMetricFamily( val gauge = GaugeMetricFamily(
"android_system_info", "android_system_info",
"Static information about the android phone", "Static information about the android phone",
listOf("manufacturer", "model", "os_release","cpu_core_count") listOf("manufacturer", "model", "os_release", "cpu_core_count")
)
gauge.addMetric(
listOf(
metricEngine.getAndroidManufacturer(),
metricEngine.getAndroidModel(),
metricEngine.getAndroidOsVersion(),
metricEngine.getNumberOfCpuCores().toString(),
), 1.0
) )
gauge.addMetric(listOf(
metricEngine.getAndroidManufacturer(),
metricEngine.getAndroidModel(),
metricEngine.getAndroidOsVersion(),
metricEngine.getNumberOfCpuCores().toString(),
), 1.0)
mfs.add(gauge) mfs.add(gauge)
} }
private fun collectHardwareSensors(mfs : MutableList<MetricFamilySamples>){ private fun collectHardwareSensors(mfs: MutableList<MetricFamilySamples>) {
metricEngine.hwSensorsValues().headingDegrees?.let { metricEngine.hwSensorsValues().headingDegrees?.let {
val gauge = GaugeMetricFamily( val gauge = GaugeMetricFamily(
"android_sensor_heading_degrees", "android_sensor_heading_degrees",
@ -284,7 +284,7 @@ class AndroidCustomExporter(private val metricEngine: MetricsEngine) : Collector
"Data from the Android Rotation Vector sensor, how is the device rotated, without a unit", "Data from the Android Rotation Vector sensor, how is the device rotated, without a unit",
listOf(), listOf(),
) )
gauge.addMetric(listOf(),it) gauge.addMetric(listOf(), it)
mfs.add(gauge) mfs.add(gauge)
} }
@ -294,12 +294,12 @@ class AndroidCustomExporter(private val metricEngine: MetricsEngine) : Collector
"Accuracy of the Android rotation vector sensor, in radians", "Accuracy of the Android rotation vector sensor, in radians",
listOf(), listOf(),
) )
gauge.addMetric(listOf(),it) gauge.addMetric(listOf(), it)
mfs.add(gauge) mfs.add(gauge)
} }
} }
private fun collectScrapeDuration(mfs : MutableList<MetricFamilySamples>, startTime : Long){ private fun collectScrapeDuration(mfs: MutableList<MetricFamilySamples>, startTime: Long) {
val gauge = GaugeMetricFamily( val gauge = GaugeMetricFamily(
"android_scrape_duration_seconds", "android_scrape_duration_seconds",
"Duration of the metric scrape", "Duration of the metric scrape",
@ -311,7 +311,7 @@ class AndroidCustomExporter(private val metricEngine: MetricsEngine) : Collector
mfs.add(gauge) mfs.add(gauge)
} }
private fun addAxisSpecificGauge(gauge: GaugeMetricFamily, data : AxisSpecificGauge){ private fun addAxisSpecificGauge(gauge: GaugeMetricFamily, data: AxisSpecificGauge) {
gauge.addMetric(listOf("x"), data.x) gauge.addMetric(listOf("x"), data.x)
gauge.addMetric(listOf("y"), data.y) gauge.addMetric(listOf("y"), data.y)
gauge.addMetric(listOf("z"), data.z) gauge.addMetric(listOf("z"), data.z)

View File

@ -24,35 +24,35 @@ import android.util.Log
private const val TAG = "METRICS_ENGINE" private const val TAG = "METRICS_ENGINE"
data class AxisSpecificGauge( data class AxisSpecificGauge(
val x : Double, val x: Double,
val y : Double, val y: Double,
val z : Double, val z: Double,
) )
class HwSensorsCache( class HwSensorsCache(
var headingDegrees : Double? = null, var headingDegrees: Double? = null,
var headingAccuracyDegrees : Double? = null, var headingAccuracyDegrees: Double? = null,
var hingeAngleDegrees : Double? = null, var hingeAngleDegrees: Double? = null,
var offbodyDetect : Double? = null, var offbodyDetect: Double? = null,
var ambientTemperatureCelsius : Double? = null, var ambientTemperatureCelsius: Double? = null,
var relativeHumidityPercent : Double? = null, var relativeHumidityPercent: Double? = null,
var accelerometer : AxisSpecificGauge? = null, var accelerometer: AxisSpecificGauge? = null,
var magneticFieldMicroTesla : AxisSpecificGauge? = null, var magneticFieldMicroTesla: AxisSpecificGauge? = null,
var gyroscopeRadiansPerSecond: AxisSpecificGauge? = null, var gyroscopeRadiansPerSecond: AxisSpecificGauge? = null,
var ambientLightLux : Double? = null, var ambientLightLux: Double? = null,
var pressureHectoPascal : Double? = null, var pressureHectoPascal: Double? = null,
var proximityCentimeters : Double? = null, var proximityCentimeters: Double? = null,
var gravityAcceleration : AxisSpecificGauge? = null, var gravityAcceleration: AxisSpecificGauge? = null,
var linearAcceleration : AxisSpecificGauge? = null, var linearAcceleration: AxisSpecificGauge? = null,
var rotationVectorValues : AxisSpecificGauge? = null, var rotationVectorValues: AxisSpecificGauge? = null,
var rotationVectorCosinusThetaHalf : Double? = null, var rotationVectorCosinusThetaHalf: Double? = null,
var rotationVectorAccuracyRadians : Double? = null, var rotationVectorAccuracyRadians: Double? = null,
); );
private val supportedSensors : List<Int> = listOf( private val supportedSensors: List<Int> = listOf(
Sensor.TYPE_HEADING, Sensor.TYPE_HEADING,
Sensor.TYPE_HINGE_ANGLE, Sensor.TYPE_HINGE_ANGLE,
Sensor.TYPE_LOW_LATENCY_OFFBODY_DETECT, Sensor.TYPE_LOW_LATENCY_OFFBODY_DETECT,
@ -69,18 +69,19 @@ private val supportedSensors : List<Int> = listOf(
Sensor.TYPE_ROTATION_VECTOR, Sensor.TYPE_ROTATION_VECTOR,
) )
val temperatureTypes : Map<Int, String> = mapOf( val temperatureTypes: Map<Int, String> = mapOf(
HardwarePropertiesManager.DEVICE_TEMPERATURE_BATTERY to "battery", HardwarePropertiesManager.DEVICE_TEMPERATURE_BATTERY to "battery",
HardwarePropertiesManager.DEVICE_TEMPERATURE_CPU to "cpu", HardwarePropertiesManager.DEVICE_TEMPERATURE_CPU to "cpu",
HardwarePropertiesManager.DEVICE_TEMPERATURE_GPU to "gpu", HardwarePropertiesManager.DEVICE_TEMPERATURE_GPU to "gpu",
HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN to "skin", HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN to "skin",
) )
class MetricsEngine(private val context: Context) : SensorEventListener { class MetricsEngine(private val context: Context) : SensorEventListener {
private val sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager private val sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
private val hwSensorsCache = HwSensorsCache() private val hwSensorsCache = HwSensorsCache()
private val hwPropertiesManager = context.getSystemService(Context.HARDWARE_PROPERTIES_SERVICE) as HardwarePropertiesManager private val hwPropertiesManager =
context.getSystemService(Context.HARDWARE_PROPERTIES_SERVICE) as HardwarePropertiesManager
init { init {
registerAllHwEventHandlers() registerAllHwEventHandlers()
@ -204,7 +205,6 @@ class MetricsEngine(private val context: Context) : SensorEventListener {
return batteryRatio.toDouble() return batteryRatio.toDouble()
} }
//TODO
fun getBatteryIsCharging(): Boolean { fun getBatteryIsCharging(): Boolean {
val batteryStatus: Intent? = IntentFilter(Intent.ACTION_BATTERY_CHANGED).let { intFilter -> val batteryStatus: Intent? = IntentFilter(Intent.ACTION_BATTERY_CHANGED).let { intFilter ->
context.registerReceiver(null, intFilter) context.registerReceiver(null, intFilter)
@ -222,7 +222,7 @@ class MetricsEngine(private val context: Context) : SensorEventListener {
return SystemClock.elapsedRealtime() / 1000.0 return SystemClock.elapsedRealtime() / 1000.0
} }
fun getAndroidOsVersion(): String{ fun getAndroidOsVersion(): String {
return Build.VERSION.RELEASE return Build.VERSION.RELEASE
} }
@ -230,38 +230,40 @@ class MetricsEngine(private val context: Context) : SensorEventListener {
return Build.MODEL return Build.MODEL
} }
fun getAndroidManufacturer() : String { fun getAndroidManufacturer(): String {
return Build.MANUFACTURER return Build.MANUFACTURER
} }
fun getHasCellularConnected() : Boolean? { fun getHasCellularConnected(): Boolean? {
val connectivityManager = context val connectivityManager = context
.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager? .getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager?
return if (connectivityManager != null){ return if (connectivityManager != null) {
val network = connectivityManager.activeNetwork val network = connectivityManager.activeNetwork
val cap = connectivityManager.getNetworkCapabilities(network) val cap = connectivityManager.getNetworkCapabilities(network)
cap != null && cap.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) cap != null && cap.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
}else{ } else {
null null
} }
} }
fun getHasWiFiConnected() : Boolean? { fun getHasWiFiConnected(): Boolean? {
val connectivityManager = context val connectivityManager = context
.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager? .getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager?
return if (connectivityManager != null){ return if (connectivityManager != null) {
val network = connectivityManager.activeNetwork val network = connectivityManager.activeNetwork
val cap = connectivityManager.getNetworkCapabilities(network) val cap = connectivityManager.getNetworkCapabilities(network)
cap != null && (cap.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) || cap.hasTransport(NetworkCapabilities.TRANSPORT_WIFI_AWARE)) cap != null && (cap.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) || cap.hasTransport(
NetworkCapabilities.TRANSPORT_WIFI_AWARE
))
}else{ } else {
null null
} }
} }

View File

@ -7,7 +7,6 @@ import android.util.Log
import io.ktor.client.HttpClient import io.ktor.client.HttpClient
import io.ktor.client.call.body import io.ktor.client.call.body
import io.ktor.client.engine.android.Android import io.ktor.client.engine.android.Android
import io.ktor.client.engine.cio.CIO
import io.ktor.client.request.post import io.ktor.client.request.post
import io.ktor.client.request.request import io.ktor.client.request.request
import io.ktor.client.request.setBody import io.ktor.client.request.setBody
@ -179,7 +178,7 @@ class PushProxClient(private val pushProxConfig: PushProxConfig) {
// push metrics to pushprox // push metrics to pushprox
// only try to push metrics if device is connected to the network // only try to push metrics if device is connected to the network
if (Util.deviceIsConnectedToInternet(context.getContext())){ if (Util.deviceIsConnectedToInternet(context.getContext())) {
try { try {
val scrapeId: String = getIdFromResponseBody(pollResponseBody) val scrapeId: String = getIdFromResponseBody(pollResponseBody)
val pushRequestBody: String = composeRequestBody(scrapedMetrics, scrapeId) val pushRequestBody: String = composeRequestBody(scrapedMetrics, scrapeId)
@ -199,7 +198,7 @@ class PushProxClient(private val pushProxConfig: PushProxConfig) {
Log.v(TAG, "Push exception $e") Log.v(TAG, "Push exception $e")
return return
} }
}else{ } else {
counters.pushError() counters.pushError()
Log.d(TAG, "device is not connected to any network") Log.d(TAG, "device is not connected to any network")
} }

View File

@ -87,7 +87,8 @@ data class RemoteWriteConfiguration(
class RemoteWriteSender(private val config: RemoteWriteConfiguration) { class RemoteWriteSender(private val config: RemoteWriteConfiguration) {
private val lastTimeRingBuffer = LastTimeRingBuffer(config.scrapeInterval) private val lastTimeRingBuffer = LastTimeRingBuffer(config.scrapeInterval)
private val storage: RemoteWriteSenderStorage = RemoteWriteSenderSimpleMemoryStorage(config.targetLabels) private val storage: RemoteWriteSenderStorage =
RemoteWriteSenderSimpleMemoryStorage(config.targetLabels)
private var scrapesAreBeingSent: Boolean = false private var scrapesAreBeingSent: Boolean = false
private lateinit var client: HttpClient private lateinit var client: HttpClient
private var lastTimeRemoteWriteSent: Long = 0 private var lastTimeRemoteWriteSent: Long = 0
@ -232,7 +233,7 @@ class RemoteWriteSender(private val config: RemoteWriteConfiguration) {
// only send the request if device is online, otherwise throw exception // only send the request if device is online, otherwise throw exception
// ExponentialBackoff will catch the exception // ExponentialBackoff will catch the exception
if (Util.deviceIsConnectedToInternet(config.getContext())){ if (Util.deviceIsConnectedToInternet(config.getContext())) {
val response = client.post(config.remoteWriteEndpoint) { val response = client.post(config.remoteWriteEndpoint) {
setBody(body) setBody(body)
headers { headers {
@ -261,7 +262,7 @@ class RemoteWriteSender(private val config: RemoteWriteConfiguration) {
throw TryExportMetricsAgainException("Status code: ${response.status.description}") throw TryExportMetricsAgainException("Status code: ${response.status.description}")
} }
} }
}else{ } else {
throw TryExportMetricsAgainException("Device is not connected to any network") throw TryExportMetricsAgainException("Device is not connected to any network")
} }
} }

View File

@ -12,29 +12,32 @@ private typealias ConverterHashMap = HashMap<List<TimeSeriesLabel>, MutableList<
private const val TAG: String = "REMOTE_WRITE_SENDER_MEMORY_SIMPLE_STORAGE" private const val TAG: String = "REMOTE_WRITE_SENDER_MEMORY_SIMPLE_STORAGE"
class RemoteWriteSenderSimpleMemoryStorage(val targetLabels: Map<String, String>) : RemoteWriteSenderStorage() { class RemoteWriteSenderSimpleMemoryStorage(val targetLabels: Map<String, String>) :
RemoteWriteSenderStorage() {
private val data: Queue<MetricsScrape> = LinkedList() private val data: Queue<MetricsScrape> = LinkedList()
private fun filterExpiredMetrics(metrics: MutableList<MetricsScrape>) { companion object {
val now: Long = System.currentTimeMillis() fun filterExpiredMetrics(metrics: MutableList<MetricsScrape>) {
val oldestMetricTimeMs: Long = now - maxMetricsAge * 1000 val now: Long = System.currentTimeMillis()
var howManyMetricsRemove = 0 val oldestMetricTimeMs: Long = now - maxMetricsAge * 1000
var howManyMetricsRemove = 0
// count how many metrics to remove // count how many metrics to remove
for (i in 0 until metrics.size) { for (i in 0 until metrics.size) {
val scrape: MetricsScrape = metrics[i] val scrape: MetricsScrape = metrics[i]
if (scrape.timeSeriesList.isNotEmpty()) { if (scrape.timeSeriesList.isNotEmpty()) {
if (scrape.timeSeriesList.first().sample.timeStampMs < oldestMetricTimeMs) { if (scrape.timeSeriesList.first().sample.timeStampMs < oldestMetricTimeMs) {
howManyMetricsRemove++ howManyMetricsRemove++
} else { } else {
break // I suppose scrapes were performed one after another break // I suppose scrapes were performed one after another
}
} }
} }
}
// remove metrics // remove metrics
for (i in 1..howManyMetricsRemove) { for (i in 1..howManyMetricsRemove) {
metrics.removeFirst() metrics.removeFirst()
}
} }
} }
@ -107,7 +110,7 @@ class RemoteWriteSenderSimpleMemoryStorage(val targetLabels: Map<String, String>
return hashmapToProtobufWriteRequest(hashmap) return hashmapToProtobufWriteRequest(hashmap)
} }
private fun addTargetLabels(labels: MutableList<TimeSeriesLabel>){ private fun addTargetLabels(labels: MutableList<TimeSeriesLabel>) {
targetLabels.forEach { targetLabels.forEach {
val label = TimeSeriesLabel( val label = TimeSeriesLabel(
value = it.value, value = it.value,

View File

@ -1,3 +1,5 @@
// Author: Martin Ptacek
package com.birdthedeveloper.prometheus.android.exporter.worker package com.birdthedeveloper.prometheus.android.exporter.worker
import org.junit.Assert import org.junit.Assert

View File

@ -1,41 +1,43 @@
// Author: Martin Ptacek
package com.birdthedeveloper.prometheus.android.exporter.worker package com.birdthedeveloper.prometheus.android.exporter.worker
import org.junit.Assert.* import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Test import org.junit.Test
class RemoteWriteSenderStorageTest{ class RemoteWriteSenderStorageTest {
// @Test @Test
// fun `basic test filterExpiredMetrics`(){ fun `basic test filterExpiredMetrics`() {
// val metrics : MutableList<MetricsScrape> = mutableListOf( val metrics: MutableList<MetricsScrape> = mutableListOf(
// // MetricSamples must be ordered // MetricSamples must be ordered
// createDummyMetricsScrape(70), createDummyMetricsScrape(70),
// createDummyMetricsScrape(50), createDummyMetricsScrape(50),
// createDummyMetricsScrape(30), createDummyMetricsScrape(30),
// ) )
//
// // execute SUT
// RemoteWriteSenderStorage.filterExpiredMetrics(metrics)
//
// assertEquals(2, metrics.size)
//
// // assert the right order
// val firstTimeStamp = metrics[0].timeSeriesList[0].sample.timeStampMs
// val secondTimeStamp = metrics[1].timeSeriesList[0].sample.timeStampMs
// assertTrue(firstTimeStamp < secondTimeStamp)
// }
// private fun createDummyMetricsScrape(ageInMinutes : Int) : MetricsScrape{ RemoteWriteSenderSimpleMemoryStorage.filterExpiredMetrics(metrics)
// return MetricsScrape(
// timeSeriesList = listOf( assertEquals(2, metrics.size)
// StorageTimeSeries(
// labels = listOf(), // assert the right order
// sample = TimeSeriesSample( val firstTimeStamp = metrics[0].timeSeriesList[0].sample.timeStampMs
// // too old val secondTimeStamp = metrics[1].timeSeriesList[0].sample.timeStampMs
// timeStampMs = System.currentTimeMillis() - ageInMinutes * 60 * 1000L, assertTrue(firstTimeStamp < secondTimeStamp)
// value = 0.0, }
// ),
// ) private fun createDummyMetricsScrape(ageInMinutes: Int): MetricsScrape {
// ) return MetricsScrape(
// ) timeSeriesList = listOf(
// } StorageTimeSeries(
labels = listOf(),
sample = TimeSeriesSample(
// too old
timeStampMs = System.currentTimeMillis() - ageInMinutes * 60 * 1000L,
value = 0.0,
),
)
)
)
}
} }