micrometer-metrics/micrometer

Better support for working with Observation from Kotlin

Open

#4754 opened on Feb 15, 2024

View on GitHub
 (21 comments) (8 reactions) (0 assignees)Java (4,220 stars) (935 forks)batch import
enhancementhelp wantedkotlinmodule: micrometer-observation

Description

Right now (as far as I can tell), there is no extra support for using Observation API from Kotlin code.

For example, to create a new Observation in normal, blocking code, one first needs to invent a convenience function like this:

private fun <T> ObservationRegistry.observeNotNull(name: String, block: () -> T): T =
    Observation.start(name, this).observe(Supplier { block() })!!

And when it comes to wrapping a suspending block of code within Observation it gets even more complicated:

private suspend fun <T> ObservationRegistry.observe(name: String, block: suspend () -> T): T {
    val observation = Observation.createNotStarted(name, this)
    observation.start()
    return try {
        mono(observationRegistry.asContextElement() + Dispatchers.Unconfined) {
            block()
        }.contextWrite { context ->
            // XXX this seems to be the safest option of making the new observation current
            context.put(ObservationThreadLocalAccessor.KEY, observation)
        }.awaitSingle()
    } catch (error: Throwable) {
        throw error
    } finally {
        // XXX or maybe it's safer to stop this in `doOnTerminate` of the created mono?
        observation.stop()
    }
}

At the same time, when working with Otel APIs directly, there is an option to construct a span/context and put it into scope via Otel's ContextExtensions.kt

Contributor guide