Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to perform basic custom instrumentation with Transaction and Spans #83

Open
2 tasks
buenaflor opened this issue Apr 27, 2023 · 1 comment · May be fixed by #155
Open
2 tasks

Add ability to perform basic custom instrumentation with Transaction and Spans #83

buenaflor opened this issue Apr 27, 2023 · 1 comment · May be fixed by #155

Comments

@buenaflor
Copy link
Contributor

buenaflor commented Apr 27, 2023

This would allow developers to create custom transactions and spans in their code to capture information about their application's performance and behavior.

At the very least support:

  • Transaction
  • Span
  • startTransaction()
  • startChild()
  • getSpan()
  • tracesSampleRate option
  • tracesSampler option

Align implementation with:

Blocked by

Preview Give feedback
@Legion2
Copy link

Legion2 commented Apr 28, 2023

Please also provide withTrace and withSpan kotlin extensions which make it easy to instrument code with an concise and kotin idomatic syntax. These extensions should also support kotlin coroutines and propagate context in coroutines correctly. I started an implementation my self, here is what I did sofar:

data class SpanContext(val span: Span) : AbstractCoroutineContextElement(SpanContext) {
    companion object Key : CoroutineContext.Key<SpanContext>
}

fun CoroutineContext.currentSpan(): Span {
    return get(SpanContext)?.span ?: throw IllegalStateException("No active Span in context")
}

suspend fun <T> withTrace(
    name: String,
    spanName: String,
    block: suspend CoroutineScope.() -> T
): T {
    val trace = startTrace(name, spanName)
    return withSpan(trace, block)
}

suspend fun <T> withSpan(name: String, block: suspend CoroutineScope.() -> T): T {
    val span = currentCoroutineContext().currentSpan()
    val childSpan = span.startChild(name)
    return withSpan(childSpan, block)
}

suspend fun <T> withSpan(span: Span, block: suspend CoroutineScope.() -> T): T {
    return try {
        withContext(SpanContext(span), block)
    } catch (e: Throwable) {
        if (e is CancellationException) {
            span.setStatus("cancelled")
        } else {
            span.setThrowable(e)
            span.setStatus("error")
        }
        throw e
    } finally {
        span.finish()
    }
}

This allows to add the context to the coroutine context, which ensures it is propagates in suspend code with structured concurrency. This means the child span must no be propagated manually. The extension functions allow to instrument code as follows:

suspend fun getData(): String {
  return withSpan("getData") {
    delay(1000)
    "foo"
  }
}

@kahest kahest moved this from Needs Discussion to Backlog in Mobile & Cross Platform SDK Sep 26, 2023
@buenaflor buenaflor linked a pull request Nov 23, 2023 that will close this issue
6 tasks
@buenaflor buenaflor self-assigned this Dec 7, 2023
@buenaflor buenaflor moved this from Backlog to In Progress in Mobile & Cross Platform SDK Dec 7, 2023
@buenaflor buenaflor moved this from In Progress to Needs Review in Mobile & Cross Platform SDK Dec 11, 2023
@buenaflor buenaflor moved this from Needs Review to Todo in Mobile & Cross Platform SDK Dec 19, 2023
@buenaflor buenaflor moved this from Todo to Backlog in Mobile & Cross Platform SDK Dec 22, 2023
@buenaflor buenaflor moved this from Backlog to Blocked in Mobile & Cross Platform SDK Feb 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Blocked
Development

Successfully merging a pull request may close this issue.

2 participants