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

ai.platon.pulsar.skeleton.common.metrics.AppMetricRegistry.kt Maven / Gradle / Ivy

package ai.platon.pulsar.skeleton.common.metrics

import ai.platon.pulsar.common.DateTimes
import ai.platon.pulsar.common.prependReadableClassName
import com.codahale.metrics.*
import kotlin.reflect.KClass

class AppMetricRegistry : MetricRegistry() {

    private val elapsedToday get() = DateTimes.elapsedToday.seconds.coerceAtMost(DateTimes.elapsed.seconds)
    private val elapsedThisHour get() = DateTimes.elapsedThisHour.seconds.coerceAtMost(DateTimes.elapsed.seconds)

    val enumCounterRegistry = EnumCounterRegistry()
    val enumCounters: MutableMap, Counter> = mutableMapOf()
    val dailyCounters = mutableSetOf()
    val hourlyCounters = mutableSetOf()

    fun name(obj: Any, name: String, separator: String = "."): String {
        return prependReadableClassName(obj, name, separator)
    }

    fun name(obj: Any, ident: String, name: String, separator: String): String {
        return prependReadableClassName(obj, ident, name, separator)
    }

    fun counter(obj: Any, ident: String, name: String): Counter {
        val fullName = name(obj, "$ident.c", name, ".")
        if (metrics.containsKey(fullName)) {
            return metrics[fullName] as Counter
        }

        val counter = counter(fullName)
        when {
            "daily" in fullName -> dailyCounters.add(counter)
            "hourly" in fullName -> hourlyCounters.add(counter)
        }
        return counter
    }

    fun counter(obj: Any, name: String) = counter(obj, "", name)

    fun meter(obj: Any, ident: String, name: String): Meter {
        val fullName = name(obj, "$ident.m", name, ".")
        return (metrics[fullName] as? Meter) ?: meter(fullName)
    }

    fun meter(obj: Any, name: String) = meter(obj, "", name)

    fun histogram(obj: Any, ident: String, name: String): Histogram {
        val fullName = name(obj, "$ident.h", name, ".")
        return (metrics[fullName] as? Histogram) ?: histogram(fullName)
    }

    fun histogram(obj: Any, name: String) = histogram(obj, "", name)

    fun  register(obj: Any, name: String, metric: T) = register(obj, "", name, metric)

    fun  register(obj: Any, ident: String, name: String, metric: T) {
        val fullName = name(obj, ident, name, ".")
        if (!metrics.containsKey(fullName)) {
            register(fullName, metric)
        }
    }

    fun  registerAll(obj: Any, metrics: Map) =
        metrics.forEach { (name, metric) -> register(obj, name, metric) }

    fun  registerAll(obj: Any, ident: String, metrics: Map) =
        metrics.forEach { (name, metric) -> register(obj, ident, name, metric) }

    fun > register(counterClass: Class, ident: String = "", withGauges: Boolean = false) {
        enumCounterRegistry.register(counterClass)
        val enumConstants = counterClass.enumConstants
        if (withGauges) {
            enumConstants.associateWithTo(enumCounters) { counterAndGauge(counterClass, ident, it.name) }
        } else {
            enumConstants.associateWithTo(enumCounters) { counter(counterClass, ident, it.name) }
        }
    }

    fun > register(counterClass: KClass, ident: String = "", withGauges: Boolean = false) {
        return register(counterClass.java, ident, withGauges)
    }

    fun counterAndGauge(obj: Any, ident: String, name: String): Counter {
        val counter = counter(obj, ident, name)

        register(obj, "$ident.g", name, Gauge { counter.count })
        register(obj, "$ident.g", "$name/s", Gauge { 1.0 * counter.count / elapsedSeconds(counter) })

        return counter
    }

    private fun elapsedSeconds(counter: Counter): Long {
        val fullName = metrics.entries.firstOrNull { it.value == counter }?.key ?: ""
        return when {
            "daily" in fullName -> elapsedToday
            "hourly" in fullName -> elapsedThisHour
            else -> DateTimes.elapsed.seconds
        }.coerceAtLeast(1)
    }

    fun counterAndGauge(obj: Any, name: String) = counterAndGauge(obj, "", name)

    fun dailyCounterAndGauge(obj: Any, ident: String, name: String) = counterAndGauge(obj, "$ident.daily", name)

    fun dailyCounterAndGauge(obj: Any, name: String) = dailyCounterAndGauge(obj, "", name)

    fun hourlyCounterAndGauge(obj: Any, ident: String, name: String) = counterAndGauge(obj, "$ident.hourly", name)

    fun hourlyCounterAndGauge(obj: Any, name: String) = hourlyCounterAndGauge(obj, "", name)

    fun multiMetric(obj: Any, ident: String, name: String): MultiMetric {
        val counter = counterAndGauge(obj, ident, name)
        val dailyCounter = dailyCounterAndGauge(obj, ident, name)
        val hourlyCounter = hourlyCounterAndGauge(obj, ident, name)
        val meter = meter(obj, ident, name)
        return MultiMetric(counter, dailyCounter, hourlyCounter, meter)
    }

    fun multiMetric(obj: Any, name: String) = multiMetric(obj, "", name)

    fun resetDailyCounters() {
        dailyCounters.forEach { it.dec(it.count) }
    }

    fun resetHourlyCounters() {
        hourlyCounters.forEach { it.dec(it.count) }
    }

    fun > setValue(counter: T, value: Int) {
        enumCounterRegistry.setValue(counter, value)
        enumCounters[counter]?.let { it.dec(it.count); it.inc(value.toLong()) }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy