This commit is contained in:
Martin Ptáček
2023-07-10 09:53:57 +02:00
parent d7c0af105e
commit abf44459c9
3 changed files with 85 additions and 127 deletions

View File

@ -8,13 +8,25 @@ import androidx.room.PrimaryKey
import androidx.room.Query
import androidx.room.Room
import androidx.room.RoomDatabase
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import remote.write.RemoteWrite.TimeSeries
//TODO
/// Room is a relational database
/// Contains the following tables:
/// - Timeseries table:
/// + labels : List<TimeSeriesLabel> sorted alphabetically and encoded in json
/// - Sample table:
/// + id
/// + timestamp
/// + value
/// + Timeseries foreign key
@Entity
data class RoomTimeSeries {
}
data class RoomTimeSeries (
@PrimaryKey(autoGenerate = false)
val labels : String
)
@Entity
data class RoomSample(
@ -24,12 +36,16 @@ data class RoomSample(
val value : Double,
)
@Serializable
data class TimeSeriesLabelList(
val labels: List<TimeSeriesLabel>
)
@Database(
entities = [RoomTimeSeries::class, RoomSample::class],
version = 1
)
abstract class RemoteWriteDatabase: RoomDatabase() {
abstract val dao: RoomDao
}
@ -41,7 +57,7 @@ interface RoomDao {
}
@Query("") //TODO
fun getNumberOfTimeSeriesSamples(){
fun getNumberOfTimeSeriesSamples(number : Int){
}
@ -53,31 +69,27 @@ interface RoomDao {
}
class RemoteWriteSenderDbStorage(getContext: () -> Context) : RemoteWriteSenderStorage(){
companion object{
const val dbName = "prometheus.db"
}
private val roomDb by lazy {
Room.databaseBuilder(
getContext(),
RemoteWriteDatabase::class.java,
"contacts.db"
dbName,
).build()
}
private fun encodeLabels(labelsList: List<TimeSeriesLabel>) : String{
//TODO
var result : String = ""
for (label in labelsList){
// check if label contains escape character
if (label.name.contains("-") || label.value.contains("-")){
throw IllegalArgumentException("Time series labels should not contain \'-\'")
}else{
//TODO
}
}
return result
/// preserve the same order
val sorted : List<TimeSeriesLabel> = labelsList.sortedBy { it.name }
val timeSeriesLabelList = TimeSeriesLabelList(labels = sorted)
return Json.encodeToString(TimeSeriesLabelList.serializer(), timeSeriesLabelList)
}
private fun decodeLabels(labels : String) : List<TimeSeriesLabel> {
//TODO
return Json.decodeFromString<TimeSeriesLabelList>(labels).labels
}
override fun writeScrapedSample(metricsScrape: MetricsScrape) {
TODO("Not yet implemented")
@ -98,5 +110,4 @@ class RemoteWriteSenderDbStorage(getContext: () -> Context) : RemoteWriteSenderS
override fun getLength(): Int {
TODO("Not yet implemented")
}
}

View File

@ -8,11 +8,17 @@ import java.util.Queue
// HashMap<List of labels including name, List of TimeSeries samples to this TimeSeries>
private typealias ConverterHashMap = HashMap<List<TimeSeriesLabel>, MutableList<TimeSeriesSample>>
class RemoteWriteSenderMemStorage : RemoteWriteSenderStorage() {
private const val TAG : String = "REMOTE_WRITE_SENDER_MEMORY_SIMPLE_STORAGE";
//TODO sort this out
class RemoteWriteSenderSimpleMemoryStorage : RemoteWriteSenderStorage() {
private val data: Queue<MetricsScrape> = LinkedList()
private fun filterExpiredMetrics(metrics : MutableList<MetricsScrape>){
val now : Long = System.currentTimeMillis()
val oldestMetricTimeMs : Long = now() - maxMetricsAge * 1000
val oldestMetricTimeMs : Long = now - maxMetricsAge * 1000
var howManyMetricsRemove : Int = 0
// count how many metrics to remove
@ -33,10 +39,9 @@ class RemoteWriteSenderMemStorage : RemoteWriteSenderStorage() {
}
}
private fun hashMapEntryToProtobufTimeSeries(
labels: List<TimeSeriesLabel>, samples: MutableList<TimeSeriesSample>
): TimeSeries {
): RemoteWrite.TimeSeries {
val timeSeriesBuilder: RemoteWrite.TimeSeries.Builder = RemoteWrite.TimeSeries.newBuilder()
@ -51,8 +56,8 @@ class RemoteWriteSenderMemStorage : RemoteWriteSenderStorage() {
return timeSeriesBuilder.build()
}
private fun hashmapToProtobufWriteRequest(hashMap: ConverterHashMap): WriteRequest {
val writeRequestBuilder: WriteRequest.Builder = WriteRequest.newBuilder()
private fun hashmapToProtobufWriteRequest(hashMap: ConverterHashMap): RemoteWrite.WriteRequest {
val writeRequestBuilder: RemoteWrite.WriteRequest.Builder = RemoteWrite.WriteRequest.newBuilder()
for (entry in hashMap) {
val timeSeries = hashMapEntryToProtobufTimeSeries(entry.key, entry.value)
@ -62,6 +67,47 @@ class RemoteWriteSenderMemStorage : RemoteWriteSenderStorage() {
return writeRequestBuilder.build()
}
override fun getScrapedSamplesCompressedProtobuf(howMany: Int): ByteArray {
if (howMany < 1) {
throw IllegalArgumentException("howMany must be bigger than zero")
}
val scrapedMetrics: MutableList<MetricsScrape> = mutableListOf()
for (i in 1..howMany) {
val oneMetric: MetricsScrape? = data.poll()
if (oneMetric == null) {
break
} else {
scrapedMetrics.add(oneMetric)
}
}
Log.d(TAG, "Getting scraped samples: ${scrapedMetrics.size} samples")
filterExpiredMetrics(scrapedMetrics)
val writeRequest: RemoteWrite.WriteRequest = metricsScrapeListToProtobuf(scrapedMetrics.toList())
val bytes: ByteArray = writeRequest.toByteArray()
return RemoteWriteSenderStorage.encodeWithSnappy(bytes)
}
private fun metricsScrapeListToProtobuf(input: List<MetricsScrape>): RemoteWrite.WriteRequest {
if (input.isEmpty()) {
throw Exception("Input is empty!")
}
val hashmap: ConverterHashMap = HashMap()
for (metricsScrape in input) {
for (timeSeries in metricsScrape.timeSeriesList){
processStorageTimeSeries(hashmap, timeSeries)
}
}
val result: RemoteWrite.WriteRequest = hashmapToProtobufWriteRequest(hashmap)
return result
}
private fun processStorageTimeSeries(hashMap: ConverterHashMap, timeSeries: StorageTimeSeries){
// add remote write label to labels
@ -80,107 +126,6 @@ class RemoteWriteSenderMemStorage : RemoteWriteSenderStorage() {
}
}
private fun metricsScrapeListToProtobuf(input: List<MetricsScrape>): WriteRequest {
if (input.isEmpty()) {
throw Exception("Input is empty!")
}
val hashmap: ConverterHashMap = HashMap()
for (metricsScrape in input) {
for (timeSeries in metricsScrape.timeSeriesList){
processStorageTimeSeries(hashmap, timeSeries)
}
}
val result: WriteRequest = hashmapToProtobufWriteRequest(hashmap)
return result
}
private val data: Queue<MetricsScrape> = LinkedList()
override fun getScrapedSamplesCompressedProtobuf(howMany: Int): ByteArray {
if (howMany < 1) {
throw IllegalArgumentException("howMany must be bigger than zero")
}
val scrapedMetrics: MutableList<MetricsScrape> = mutableListOf()
for (i in 1..howMany) {
val oneMetric: MetricsScrape? = data.poll()
if (oneMetric == null) {
break
} else {
scrapedMetrics.add(oneMetric)
}
}
Log.d(TAG, "Getting scraped samples: ${scrapedMetrics.size} samples")
filterExpiredMetrics(scrapedMetrics)
val writeRequest: WriteRequest = this.metricsScrapeListToProtobuf(scrapedMetrics.toList())
val bytes: ByteArray = writeRequest.toByteArray()
return this.encodeWithSnappy(bytes)
}
override fun removeNumberOfScrapedSamples(number: Int) {
if (number > 0) {
for (i in 1..number) {
if(data.isEmpty()){
break;
}else{
data.remove()
}
}
} else {
throw IllegalArgumentException("number must by higher than 0")
}
}
override fun writeScrapedSample(metricsScrape: MetricsScrape) {
Log.d(TAG, "Writing scraped sample to storage")
data.add(metricsScrape)
}
override fun isEmpty(): Boolean {
return data.isEmpty()
}
override fun getLength(): Int {
return data.count()
}
}
//TODO sort this out
class RemoteWriteSenderSimpleMemoryStorage : RemoteWriteSenderStorage() {
private val data: Queue<MetricsScrape> = LinkedList()
override fun getScrapedSamplesCompressedProtobuf(howMany: Int): ByteArray {
if (howMany < 1) {
throw IllegalArgumentException("howMany must be bigger than zero")
}
val scrapedMetrics: MutableList<MetricsScrape> = mutableListOf()
for (i in 1..howMany) {
val oneMetric: MetricsScrape? = data.poll()
if (oneMetric == null) {
break
} else {
scrapedMetrics.add(oneMetric)
}
}
Log.d(TAG, "Getting scraped samples: ${scrapedMetrics.size} samples")
filterExpiredMetrics(scrapedMetrics)
val writeRequest: RemoteWrite.WriteRequest = this.metricsScrapeListToProtobuf(scrapedMetrics.toList())
val bytes: ByteArray = writeRequest.toByteArray()
return this.encodeWithSnappy(bytes)
}
//TODO use this thing
override fun removeNumberOfScrapedSamples(number: Int) {
if (number > 0) {

View File

@ -2,6 +2,7 @@ package com.birdthedeveloper.prometheus.android.prometheus.android.exporter.work
import android.util.Log
import io.prometheus.client.Collector.MetricFamilySamples
import kotlinx.serialization.Serializable
import org.iq80.snappy.Snappy
import remote.write.RemoteWrite.Label
import remote.write.RemoteWrite.Sample
@ -78,6 +79,7 @@ data class StorageTimeSeries(
val labels : List<TimeSeriesLabel>,
)
@Serializable
data class TimeSeriesLabel(
val name: String,
val value: String,