Attach custom child spans to the cold app start transaction
Problem Statement
Hi!
I use the performance v2 feature, and as the next step, I'd like to measure specific operations time during the application.load operation, for example, and enrich the transaction with more detailed spans.
I haven't found the proper way to do this at the moment.
Could you please suggest if there is some workaround to do that using the current API(custom callbacks or event processor?)
Expected behaviour: possibility to add child spans to the existing spans(application.load, activity.load, etc.) during cold app start.
SDK version - 7.9.0
Thank you!
Solution Brainstorm
No response
I also have some "Missing instrumentation" spans. I know which operations causes them and I'd like to have possibility to mark them explicitly as the child spans.
@zhukic thanks for reaching out! Yes, that's something we've been considering for a while, let me discuss this internally!
In the meantime you could utilize EventProcessors to add your custom spans, here's a snippet:
Beware these are internal APIs, so they might not be stable across releases.
SentryAndroid.init(this) { options ->
options.apply {
dsn = ...
addEventProcessor(object : EventProcessor {
@Suppress("UnstableApiUsage")
override fun process(
transaction: SentryTransaction,
hint: Hint
): SentryTransaction {
transaction.contexts.trace?.traceId?.let { traceId ->
transaction.spans
.firstOrNull { it?.op.equals("app.start.cold") }
?.let { appStartSpan ->
val parentSpanId = appStartSpan.spanId
val startTimeStamp = 0.0 // unix time in seconds
val endTimeStamp = 0.0 // unix time in seconds
val op = "component.op"
val description = "description"
transaction.spans.add(
SentrySpan(
startTimeStamp,
endTimeStamp,
traceId,
SpanId(),
parentSpanId,
op,
description,
SpanStatus.OK,
null,
emptyMap(),
emptyMap(),
emptyMap(),
emptyMap(),
)
)
}
}
return transaction
}
})
}
}
@zhukic could you describe your use-case a bit more in detail? Which kind of operations do you want to measure? Is it mainly about the execution of Application.onCreate()?
@markushi Thank you for the answers!
I'll try the approach with the EventProcessor a bit later.
could you describe your use-case a bit more in detail? Which kind of operations do you want to measure? Is it mainly about the execution of Application.onCreate()?
During the Application.onCreate() I initialize lots of my app's components and it takes some time. I'd like to have a possibility to measure all the initializations separately and attach them as the child spans to the application.load span.
The second use case is described here. It's my code which runs on the UI thread, and currently, it's marked as "Missing instrumentation". I'd also like to have a possibility to attach it as a child span. I guess, this can be also solved by a custom EventProcessor.
@zhukic thanks for the details, that's very helpful! On a side note - would you be interested if we provided auto-instrumentation for those components that get initialized as part of Application.onCreate? We have some ideas on how to to do that, although it may become a bit noisy, but we can think of some configuration/ignorelist.
@romtsn
would you be interested if we provided auto-instrumentation for those components that get initialized as part of Application.onCreate
Yes, I would!
We have some ideas on how to to do that, although it may become a bit noisy
What do you mean?
I'd expect that I can configure myself which parts of code to make measurable, something like this:
override fun onCreate() {
super.onCreate()
//some code
initialize1()
initialize2()
//some code
}
@ApplicationOnCreateSpan(spanOperation = "initialization1")
private fun initialize1() {
//
}
@ApplicationOnCreateSpan(spanOperation = "initialization2")
private fun initialize2() {
//
}
and application.load span would have two child spans: initialization1, initialization2
@markushi @romtsn Hi!
I've tried the solution with the custom EventProcessor, and looks like it works!
The only thing that concerns me is that there are no application.load and activity.load spans that, as I see, get attached in PerformanceAndroidEventProcessor which is called after my custom processor.
I see that there is also BeforeSendTransactionCallback which contains all the spans but I'm not sure if it's ok to modify the transaction on this stage.
So the UI looks like this for the spans which are created from Application.onCreate:
But it's good enough for now!
If you have some suggestions - would be glad to hear.
Thank you for help!
@zhukic Glad it's working for you! Actually it should be safer to use BeforeSendTransactionCallback instead of a custom EventProcessor, as the BeforeSendTransactionCallback is executed after all processors.