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

rfc(decision): Mobile - Tracing Without Performance V2 #136

Closed

Conversation

philipphofmann
Copy link
Member

@philipphofmann philipphofmann commented Jun 4, 2024

This RFC aims to find a strategy to update the so traces don’t reference hundreds of unrelated
events.

Rendered RFC

@philipphofmann philipphofmann force-pushed the rfc/mobile-tracing-without-performance-v-2 branch from f06832d to 313a0a0 Compare June 4, 2024 08:45
@philipphofmann philipphofmann requested a review from a team June 4, 2024 09:29
Copy link
Member

@kahest kahest left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some first thoughts. In general I don't see a lot of different options here - IMO it's mostly a combination of screen awareness, foreground/background handling and maybe some timeouts. So pretty much exactly your option 1

text/0136-mobile-tracing-without-performance-v-2.md Outdated Show resolved Hide resolved
Comment on lines +57 to +58
1. For single-screen applications such as social networks, the lifetime of a trace could still be
long, and multiple unrelated events could be mapped to one trace.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC this is in line with the JS implementation, and something we can accept for now. In case we have clear pointers we need to address this (and how) we can iterate

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A manual API to renew the traceId could help with these edge cases.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fyi, we have TracingUtils.startNewTrace in Java (should probably be exposed through the static API though)

Comment on lines +61 to +62
3. It doesn’t work well for declarative UI frameworks as Jetpack Compose and SwiftUI for which the
SDKs can’t reliably automatically detect when apps load a new screen.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For JPC there might be ways to make the 80% work with some KCP magic I guess (@markushi @romtsn wdyt?). But SwiftUI is a closed box and we'll need to mitigate this by providing clear ways/instructions on where to e.g. wrap something with a SDK method and/or manual API usage

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the easiest way to get started is by providing a wrapper ~SentryScreen() { <Composable> }, in a later version we could have a @SentryScreen method annotation which utilizes KCP to auto-wrap it.

@bitsandfoxes
Copy link

What about additionally tying it to foreground/background behaviour like sessions? It doesn't have to be only one rule, right? It could be a set of rules and conditions that lead to the creation of a new traceId.

text/0136-mobile-tracing-without-performance-v-2.md Outdated Show resolved Hide resolved
Comment on lines +61 to +62
3. It doesn’t work well for declarative UI frameworks as Jetpack Compose and SwiftUI for which the
SDKs can’t reliably automatically detect when apps load a new screen.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the easiest way to get started is by providing a wrapper ~SentryScreen() { <Composable> }, in a later version we could have a @SentryScreen method annotation which utilizes KCP to auto-wrap it.

text/0136-mobile-tracing-without-performance-v-2.md Outdated Show resolved Hide resolved
### Pros <a name="option-1-pros"></a>

1. Similar to [JavaScript]((https://github.com/getsentry/sentry-javascript/issues/11599)) updating
it based on routes, so it should be easy to implement for React-Native.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for flutter at the very least we would need the user to use our SentryNavigatorObserver and then set a route name, e.g

navigatorObservers: [
  SentryNavigatorObserver()
],

MaterialPageRoute(
  settings: const RouteSettings(name: 'AutoCloseScreen'),
  builder: (context) => const AutoCloseScreen()),
),

Would the default behaviour remain as it is right now if a user didn't use the navigator observer on flutter?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the current default behavior in Flutter, @buenaflor?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is similar issue with React Native. We don't have the screens/routes information without the performance instrumentation (ReactNavigation or ReactNativeNavigation).

We could update the auto instrumentation work without performance (without creating spans). Or get some signal of change from native.

Or having a public API to renew the traceId.

@philipphofmann philipphofmann marked this pull request as ready for review June 10, 2024 06:38
3. It doesn’t work well for declarative UI frameworks as Jetpack Compose and SwiftUI for which the
SDKs can’t reliably automatically detect when apps load a new screen.

# Drawbacks
Copy link
Member

@Lms24 Lms24 Jun 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We were recently made aware that another implication of long-running traces is that it potentially increases transaction/span quota usage. This is because in JS we inherit the sampling decision for the trace in subsequent transactions.

For example:

  1. Pageload transaction is sampled by rolling the dice
  2. PropagationContext stores positive sampling decision
  3. Interaction transaction is started
  4. Interaction transaction is sampled because the propagation context already holds a positive sampling decision
  5. Repeat for every started transaction until next pageload or navigation

So either we accept this and move on for now by continuing with this behaviour or we break trace consistency by again rolling the dice for new root spans/transactions.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Lms24, please clarify why this wasn't a problem before. I don't understand how this proposed change here will cause this.

Copy link
Member

@Lms24 Lms24 Jun 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might be missing a bit of context around how Tracing without Performance and the PropagationContext is implemented in mobile SDKs.

If the proposed change is purely intended for TwP scenarios and does not affect the overall trace lifetime in case a root span/transaction is started ("tracing with performance") I think we're good. That is because for TwP, we defer the sampling decision to the downstream service (i.e. send sentry-trace headers without a sampled flag).

In JS however, we changed the trace lifetime not just for TwP but in general, leading to scenarios like the one above. To illustrate further, why this is problematic, I'm gonna adjust the example a bit from above

  1. Initial Pageload transaction is sampled by rolling the dice
  2. PropagationContext stores positive sampling decision
  3. application, still on the same page but after the pageload span ended, makes an http request to a downstream service and propagates the sentry-trace header with the positive sampling decision, forcing the downstream service to positively sample their transaction.
  4. repeat 3 a lot of times (e.g. an application auto-refreshing some state every 5s) and you have a lot of sampled transactions because one initial transaction was sampled positively in the FE.

So even without an active transaction, we'd still propagate a forced sampled flag to downstream services.

Does this make sense?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the detailed explanation. Yes, that makes sense, but I guess in the long run, you should have a roughly equal amount of transactions. It shouldn't matter if you roll the dice once for 10 transactions or every time for each transaction. If you roll the dice often enough, an equal amount of transactions should be captured.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not necessarily unfortunately. This would only hold up if the sample rates on client and server were the same. If users have lower sample rates on the server, they would send significantly less server-side transactions with the previous implementation.

I tried verifying this with a small script: https://gist.github.com/Lms24/9a631295aef58cf22fb8f5307953335c

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When a span starts, SDKs should use the traceID on the PropagationContext

We should say explicitly to use only the traceId, but not the sampling decision of the PropagationContext.
Regardless of client/server side sampling, i think we would break the sampling in general, as it doesn't apply to the PropagationContext. The sampler function is particularly problematic imho

mobile SDKs use for determining the end of a session, mobile SDKs renew the `traceId` of the
PropagationContext. If the app stays in the background for shorter or equal to 30 seconds,
mobile SDKs must not renew the `traceId` of the PropagationContext when the app moves again to
the foreground. When a span starts, SDKs should use the traceID on the PropagationContext, but
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't this break transaction/spans sample rates?
The sampled state of the PropagationContext would overwrite the calculated sampling decision of the span done through tracesSampleRate - or even worse through tracesSampler

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or are we just saying to use the traceId of the PropagationContext, retaining the usual sample decision?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

continuing below

@philipphofmann
Copy link
Member Author

The RFC is on hold for now. We found some problems with the suggested approach in JS and need to revisit our approach. After we decided on how to continue we are either going to reopen this RFC or open another one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

9 participants