All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.dev.kord.cache.api.meta.MetricsCache.kt Maven / Gradle / Ivy

package dev.kord.cache.api.meta

import dev.kord.cache.api.DataCache
import dev.kord.cache.api.DataEntryCache
import dev.kord.cache.api.QueryBuilder
import dev.kord.cache.api.Query
import kotlinx.atomicfu.atomic
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.onEach
import kotlin.reflect.KType

/**
 * Wraps this cache in a [MetricsCache], enabling logging of metrics.
 */
fun DataCache.withMetrics(): MetricsCache = MetricsCache(this)

/**
 * A [DataCache] that logs usage [statistics] via its [logger].
 */
class MetricsCache(
        private val delegate: DataCache,
        private val logger: StatisticsLogger = StatisticsLogger()
) : DataCache by delegate {

    val statistics: CacheStatistics get() = logger.metaData

    override fun  getEntry(type: KType): DataEntryCache? {
        val cache = getEntry(type) ?: return null
        return MetricsEntryCache(cache, logger.getForType(type))
    }

}

private class MetricsEntryCache(
        private val delegate: DataEntryCache,
        private val logger: TypeStatisticsLogger
) : DataEntryCache by delegate {

    override fun query(): QueryBuilder {
        val builder = delegate.query()
        return MetricsQueryBuilder(builder, logger)
    }

}

private class MetricsQueryBuilder(
        private val delegate: QueryBuilder,
        private val logger: TypeStatisticsLogger
) : QueryBuilder by delegate {

    override fun build(): Query {
        val query = delegate.build()
        return MetricsQuery(query, logger)
    }

}

private class MetricsQuery(
        private val delegate: Query,
        private val logger: TypeStatisticsLogger
) : Query by delegate {

    inner class FlowConverter {
        val first = atomic(false)

        fun convert() = delegate.asFlow().onEach {
            if (first.compareAndSet(expect = false, update = true)) logger.logHit()
        }
    }

    override fun asFlow(): Flow {
        logger.logQuery()
        return FlowConverter().convert()
    }

    override suspend fun single(): V {
        logger.logQuery()
        val result = runCatching { delegate.single() }

        result.onSuccess { logger.logQuery() }
        return result.getOrElse { throw it }
    }

    override suspend fun singleOrNull(): V? {
        logger.logQuery()
        return delegate.singleOrNull()?.also {
            logger.logHit()
        }
    }

    override suspend fun toCollection(): Collection {
        logger.logQuery()
        val collection = super.toCollection()

        if (collection.isNotEmpty()) logger.logHit()
        return collection
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy