diff --git a/core/src/commonMain/kotlin/com/xebia/functional/xef/metrics/CounterMetric.kt b/core/src/commonMain/kotlin/com/xebia/functional/xef/metrics/CounterMetric.kt new file mode 100644 index 000000000..bf74f12a3 --- /dev/null +++ b/core/src/commonMain/kotlin/com/xebia/functional/xef/metrics/CounterMetric.kt @@ -0,0 +1,7 @@ +package com.xebia.functional.xef.metrics + +interface CounterMetric { + fun increment(n: Long) + + fun increment(n: Long, attributes: Map) +} diff --git a/core/src/commonMain/kotlin/com/xebia/functional/xef/metrics/InMemoryCounterMetric.kt b/core/src/commonMain/kotlin/com/xebia/functional/xef/metrics/InMemoryCounterMetric.kt new file mode 100644 index 000000000..7cd302fb3 --- /dev/null +++ b/core/src/commonMain/kotlin/com/xebia/functional/xef/metrics/InMemoryCounterMetric.kt @@ -0,0 +1,20 @@ +package com.xebia.functional.xef.metrics + +import arrow.atomic.AtomicLong +import io.github.oshai.kotlinlogging.KLogger + +class InMemoryCounterMetric(val name: String, val logger: KLogger) : CounterMetric { + private val count = AtomicLong(0) + + override fun increment(n: Long) { + count.incrementAndGet() + logger.info { "Counter $name incremented to ${count.get()}" } + } + + override fun increment(n: Long, attributes: Map) { + count.addAndGet(n) + logger.info { + "Counter $name incremented to ${count.get()} with those attributes: ${attributes.entries.joinToString( ",")}" + } + } +} diff --git a/core/src/commonMain/kotlin/com/xebia/functional/xef/metrics/LogsMetric.kt b/core/src/commonMain/kotlin/com/xebia/functional/xef/metrics/LogsMetric.kt index c64c4d194..ac18ca81f 100644 --- a/core/src/commonMain/kotlin/com/xebia/functional/xef/metrics/LogsMetric.kt +++ b/core/src/commonMain/kotlin/com/xebia/functional/xef/metrics/LogsMetric.kt @@ -18,6 +18,8 @@ class LogsMetric(private val level: Level = Level.INFO) : Metric { private val logger = KotlinLogging.logger {} + private val countersMap: MutableMap = mutableMapOf() + override suspend fun customSpan( name: String, parameters: Map, @@ -111,5 +113,17 @@ class LogsMetric(private val level: Level = Level.INFO) : Metric { logger.at(level) { message = "${writeIndent(numberOfBlocks.get())}|-- $key = $values" } } - private fun writeIndent(times: Int = 1) = (1..indentSize * times).fold("") { a, b -> "$a " } + override suspend fun createCounter(name: String): CounterMetric { + logger.at(level) { message = "${writeIndent(numberOfBlocks.get())}> Created counter: $name" } + val counter = InMemoryCounterMetric(name, logger) + countersMap[name] = counter + return counter + } + + override suspend fun getCounter(name: String): CounterMetric { + logger.at(level) { message = "${writeIndent(numberOfBlocks.get())}> Get counter: $name" } + return countersMap[name] ?: InMemoryCounterMetric(name, logger) + } + + private fun writeIndent(times: Int = 1) = (1..indentSize * times).fold("") { a, _ -> "$a " } } diff --git a/core/src/commonMain/kotlin/com/xebia/functional/xef/metrics/Metric.kt b/core/src/commonMain/kotlin/com/xebia/functional/xef/metrics/Metric.kt index e7a1f47f0..3a38359af 100644 --- a/core/src/commonMain/kotlin/com/xebia/functional/xef/metrics/Metric.kt +++ b/core/src/commonMain/kotlin/com/xebia/functional/xef/metrics/Metric.kt @@ -26,6 +26,10 @@ interface Metric { suspend fun assistantCreatedMessage(messageObject: MessageObject, source: String) + suspend fun createCounter(name: String): CounterMetric? + + suspend fun getCounter(name: String): CounterMetric? + companion object { val EMPTY: Metric = object : Metric { @@ -52,6 +56,10 @@ interface Metric { override suspend fun parameter(key: String, value: String) {} override suspend fun parameter(key: String, values: List) {} + + override suspend fun createCounter(name: String): CounterMetric? = null + + override suspend fun getCounter(name: String): CounterMetric? = null } } } diff --git a/examples/src/main/kotlin/com/xebia/functional/xef/assistants/DSL.kt b/examples/src/main/kotlin/com/xebia/functional/xef/assistants/DSL.kt index 04c13c081..849c9f5af 100644 --- a/examples/src/main/kotlin/com/xebia/functional/xef/assistants/DSL.kt +++ b/examples/src/main/kotlin/com/xebia/functional/xef/assistants/DSL.kt @@ -42,7 +42,7 @@ suspend fun main() { // - # docker-compose up val metric = com.xebia.functional.xef.metrics.Metric.EMPTY - // val metric = com.xebia.functional.xef.opentelemetry.OpenTelemetryMetric() + val questionsCounter = metric.createCounter("questions-counter") val assistant = Assistant( @@ -54,6 +54,7 @@ suspend fun main() { while (true) { println() val userInput = readln() + questionsCounter?.increment(1) thread.createMessage(userInput) runAssistantAndDisplayResults(thread, assistant) } diff --git a/server/docker/opentelemetry/docker-compose.yml b/integrations/opentelemetry/docker/docker-compose.yml similarity index 100% rename from server/docker/opentelemetry/docker-compose.yml rename to integrations/opentelemetry/docker/docker-compose.yml diff --git a/server/docker/opentelemetry/otel-collector-config.yaml b/integrations/opentelemetry/docker/otel-collector-config.yaml similarity index 100% rename from server/docker/opentelemetry/otel-collector-config.yaml rename to integrations/opentelemetry/docker/otel-collector-config.yaml diff --git a/server/docker/opentelemetry/prometheus.yaml b/integrations/opentelemetry/docker/prometheus.yaml similarity index 100% rename from server/docker/opentelemetry/prometheus.yaml rename to integrations/opentelemetry/docker/prometheus.yaml diff --git a/integrations/opentelemetry/src/main/kotlin/com/xebia/functional/xef/opentelemetry/OpenTelemetryCounter.kt b/integrations/opentelemetry/src/main/kotlin/com/xebia/functional/xef/opentelemetry/OpenTelemetryCounter.kt new file mode 100644 index 000000000..45899bcda --- /dev/null +++ b/integrations/opentelemetry/src/main/kotlin/com/xebia/functional/xef/opentelemetry/OpenTelemetryCounter.kt @@ -0,0 +1,17 @@ +package com.xebia.functional.xef.opentelemetry + +import com.xebia.functional.xef.metrics.CounterMetric +import io.opentelemetry.api.common.Attributes + +class OpenTelemetryCounter(private val longCounter: io.opentelemetry.api.metrics.LongCounter) : + CounterMetric { + override fun increment(n: Long) { + longCounter.add(n) + } + + override fun increment(n: Long, attributes: Map) { + val attributesBuilder = Attributes.builder() + attributes.forEach { (k, v) -> attributesBuilder.put(k, v) } + longCounter.add(n, attributesBuilder.build()) + } +} diff --git a/integrations/opentelemetry/src/main/kotlin/com/xebia/functional/xef/opentelemetry/OpenTelemetryMetric.kt b/integrations/opentelemetry/src/main/kotlin/com/xebia/functional/xef/opentelemetry/OpenTelemetryMetric.kt index 34f859818..a6bdbd7f0 100644 --- a/integrations/opentelemetry/src/main/kotlin/com/xebia/functional/xef/opentelemetry/OpenTelemetryMetric.kt +++ b/integrations/opentelemetry/src/main/kotlin/com/xebia/functional/xef/opentelemetry/OpenTelemetryMetric.kt @@ -3,9 +3,11 @@ package com.xebia.functional.xef.opentelemetry import com.xebia.functional.openai.generated.model.MessageObject import com.xebia.functional.openai.generated.model.RunObject import com.xebia.functional.openai.generated.model.RunStepObject +import com.xebia.functional.xef.metrics.CounterMetric import com.xebia.functional.xef.metrics.Metric import com.xebia.functional.xef.prompt.Prompt import com.xebia.functional.xef.prompt.contentAsString +import io.opentelemetry.api.metrics.Meter import io.opentelemetry.api.trace.* class OpenTelemetryMetric( @@ -18,6 +20,10 @@ class OpenTelemetryMetric( private val assistantState = OpenTelemetryAssistantState(getTracer()) + private val meter = getMeter() + + private val countersMap: MutableMap = mutableMapOf() + override suspend fun customSpan( name: String, parameters: Map, @@ -37,6 +43,14 @@ class OpenTelemetryMetric( block() } + override suspend fun createCounter(counterName: String): CounterMetric { + val counter = OpenTelemetryCounter(meter.counterBuilder(counterName).build()) + countersMap[counterName] = counter + return counter + } + + override suspend fun getCounter(counterName: String): CounterMetric? = countersMap[counterName] + override suspend fun event(message: String) { state.event(message) } @@ -61,4 +75,7 @@ class OpenTelemetryMetric( private fun getTracer(scopeName: String? = null): Tracer = openTelemetry.getTracer(scopeName ?: config.defaultScopeName) + + private fun getMeter(scopeName: String? = null): Meter = + openTelemetry.getMeter(scopeName ?: config.defaultScopeName) }