Description
In Node & edge environments, we use async local storage to ensure we have actual isolation for active spans. So the following code:
startSpan({ name: 'outer 1' }, async () => {
await waitForSeconds(2);
console.log(getActiveSpan());
});
startSpan({ name: 'outer 2' }, async () => {
await waitForSeconds(3);
console.log(getActiveSpan());
});
Will actually work and log outer 1
and outer 2
correctly.
However, in browser (and theoretically any other environment where we don't have a custom Async Context Strategy (ACS)), this will not necessarily work as expected, because we cannot isolate the execution contexts, thus they may leak out into other parts of the code - so the above code may print out different spans, depending on what is globally active at the time.
This was always the case - also with the old performance APIs - but with the new APIs it is much easier to accidentally do this.
Previously, if you just did getActiveTransaction().startChild()
or similar, stuff would work just fine - you had to actually go and do getCurrentScope().setSpan(span)
to get potentially inconsistent behavior.
Since now startSpan
(and startSpanManual
) are the "default" APIs proposed for these things, I feel like maybe this will become a bigger problem in v8, and we should address this somehow.
Some options I see:
- We do nothing - this will basically work when passing a sync callback, and it may or may not work when passing async callbacks.
- In browser environment, we make
startSpan
andstartSpanManual
not actually update the active span. This would mean that the only active spans would ever be ones that we create (? or we provide a separate API/option for that...?), so pageload/navigation spans... we'd need some story for manual page load etc. instrumentation though as well 🤔 - Or we could do 2 only if an async callback is provided, not if a sync callback is provided. But I guess this would only make things even more confusing...
Basically, I think it would be safer to say that in browser we don't have a nested span structure, but we only have a single active span (pageload, navigation, ...) and all other spans are children of that. That of course also has downsides, but to me less severe ones. But 🤷 there is no ideal solution here 😬