getsentry / sentry-javascript

Official Sentry SDKs for JavaScript
https://sentry.io
MIT License
7.99k stars 1.57k forks source link

Improve Robustness of interaction spans #13738

Open Lms24 opened 1 month ago

Lms24 commented 1 month ago

Description

Our browser SDKs offer an experimental feature in browserTracingIntegration - interaction ~transactions~ spans.

While the idea sounds great, in reality, they're currently a bit problematic and not yet robust enough to enable them by default:

Problems/Symptoms

  1. Every single click or interaction starts a span, regardless of if the click actually caused any event on the page or if it was a dead click
  2. Even if the interaction was not a dead click, chances are high that the resulting effects of the click are not worth sending the span (tree). For instance, if a click onto a button displays an element that was previously hidden, there will be no resource span, no http request span or anything else that our auto instrumentation would catch.
  3. Naming is hard. At the moment, the interaction root idle span gets the route name but a ui.interaction op. This is because we can't use the selector of the clicked element as a span name because it's high cardinality as, depending on the application, it can change very frequently.
  4. Currently, due to the v8 tracing model in the browser, interaction spans are added to the same trace as the previous pageload or navigation span.
  5. Interaction root spans are idle spans because there's no clear ending point we can use to deterministically end the span.

Solution Brainstorming

  1. We can try to add some simple heuristics around if the click was made onto an interactive element or not. This should be fairly easily testable and we could even create a user-overrideable API around selectors that should be deemed interactive.
    • Alternatively or in combination, we could let users decide which elements should even start an interaction span. For example by letting them specify a data-sentry-trace attribute on the respective html element.
      1. We can simply decide to not send an interaction span (tree) if there are no spans other than ui.interaction.* spans in the tree. Realistically, today, with our auto instrumentation, this would mean that we'd only send interaction spans if
    • a fetch/xhr request was made
    • users enabled component tracking in a framework SDK that supports the feature and the interaction causes mounts or updates of components
    • users manually instrumented operations triggered by the interaction
      1. I think this is fine as it is but happy to hear different opinions on the matter
      2. I also think that this is fine, assuming we continue to be okay with long-running traces. The alternative requires changes to the tracing model in the browser which we can and should think about but not solely for the purpose of interaction spans.
      3. While no-one really is a fan of idle spans, I think there's no alternative to having them in the browser. I think this is also fine and just something, we need to deal with product-side (i.e. not give the duration of the root span too much meaning).
Lms24 commented 1 month ago

Priority-wise this is rather low at the moment (as we discussed at our recent offsite event) but I figured I'd write down some ideas. We can revisit this whenever. Also curious on the performance team's perspective here.

gggritso commented 1 month ago

I love this! I generally want as much telemetry as possible (within reason) and UI interactions are very important telemetry. I fully agree that sending a span for every click is impractical but I really like the suggested solutions!

Knowing which interaction started a network request, or a React render, or a custom span is really useful and good. SPAs do a lot of work after pageload/navigation, and I would love for this work to be instrumented, and sent. I want to know everything my app is doing, if possible, not just what happens after load.

IMO both the suggestions (heuristics around interactive elements, and only sending span trees if they have children) are acceptable! I'd love for a member of the EAP team to chime in about cardinality, because the EAP dataset has very strong support for high-cardinality data. Also we now have a Webpack plugin that annotates component names (lower cardinality), and we can try to do some ingest-side work to reduce cardinality if needed.

All I'm saying is that I really like this idea, I think it's really valuable, and I'd love to see it. I think it would be really good for the product and developers who use it!