mirror of
https://github.com/mii443/prometheus-android-exporter.git
synced 2025-08-22 15:15:35 +00:00
final
This commit is contained in:
@ -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 {
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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")
|
||||||
}
|
}
|
||||||
|
@ -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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user