Sentry-dart: Sentry.configureScope not synchronize in native(Android).

Created on 27 Nov 2020  路  21Comments  路  Source: getsentry/sentry-dart

sentry_flutter: ^4.0.0-alpha.2

Sentry.configureScope((Scope scope) async {
    scope.user = User(id: xxx);
});

The user information was set in the flutter and did not synchronize in native(Android).

Hope to add this feature, thanks

enhancement flutter

Most helpful comment

@ueman hold on on this one for a bit, we need to discuss the right way to do it, and yesterday we didn't have time enough to discuss this further, the decision would likely affect other SDKs like Cordova, React-native etc

All 21 comments

@nEdAy thanks for this.

True, we still don't synchronize the Scope to the native layer, but we'll definitely do it.

This is needed also in order to get the scope IP address to the session in native.

Is this related to a race condition that happens between the native and Flutter SDKs?
If await is used on SentryFlutter.init(), only the Flutter scope details are sent.
If await is not called on SentryFlutter.init(), only the native details are sent.
I'm currently getting both the native and Flutter details to send by calling Sentry.configureScope before every error report call.

@searchy2 not sure if I follow, this is a feature request, not a bug, at least related to this issue.
could you open an issue describing the problem? using the issue template would be very helpful too, thanks,

Will do, thanks!

any update?

no, you could always call the Native SDKs yourself via Method channels, we'll eventually do it, just not a high priority right now, PRs are also welcome, happy to guide & review.

Do we want to implement it with ScopeObserver (like the Java implementation)?

@ueman it's not a unified behavior across SDK but usually helpful when you have multiple SDKs packaged together.
it sounds like a good idea for me, you can experiment and see how it goes, obviously, we can adapt if necessary.
when Dart is used with Flutter, it should propagate the changes (possible to turn on/off via options).
when Dart is used alone, it should not, so that's why the Interface exists.

A few thoughts on this:

Option 1a:

The Java interface has only synchronus methods, which we can't use because MethodChannels are async. That would require use to make every synchronized property of a Scope to be an async method. This would be a pretty huge breaking change.

Option 1b:

Just like 1a but we don't await the MethodChannels. This is kinda a best effort approach. No breaking changes.

Option 2:

We could do something like a Sentry.configureNativeScope():

await SentryFlutter.configureNativeScope((scope){
// everything which is done in this callback is synced to the native SDKs
});

// No callback syncs the current scope to native
await SentryFlutter.configureNativeScope();

This method would then be responsible to sync everything to the native side.

What do you think @marandaneto ? Or do you have another idea?

@ueman let's take a look at the react-native-sdk, I believe they should have the same problem, let's see what they have done.
I'd be fine not awaiting the scope to be set on native, but this has a downside, you set a user, the App. crashes right away and it didn't have time enough to sync to native, that crash report won't have the user.

ReactNative also uses option 1b. Or at least it looks like that to me. https://reactnative.dev/docs/native-modules-android mentions Promises for JS <-> Android communication which https://github.com/getsentry/sentry-react-native/blob/master/src/js/scope.ts does not use.

@jennmueng can help us out on that, how does it work on React-native? pros? cons?

If going with option 1b we need to consider back pressure. What happens if I call that in a tight loop? Is it going to overwhelm the process? If so we'd need to track how many futures are open and drop calls accordingly.

Honestly the Flutter SDK is doing things right. By having an API that returns Future across the board, allowing for async code to run on init, eventProcessors, etc. We should discuss this with a bigger audience and consider the implications of taking this approach on more SDKs.

@ueman Yes we use option 1b over in React Native. It does not use promises for syncing scope across the native layer, I believe it's the easiest and quickest way to implement scope sync across the native layer for 99% of cases unless a crash happens right away like @marandaneto's example.

But I'm not sure if I follow the discussion: If a crash does happen right away on the native layer with the scope info missing, wouldn't the crash just happen regardless and prolonging it on the upper (JS/Flutter) layer not have any effect? If it's a crash from the upper (JS/Flutter) layer, wouldn't it have the scope set already?

But I'm not sure if I follow the discussion: If a crash does happen right away on the native layer with the scope info missing, wouldn't the crash just happen regardless and prolonging it on the upper (JS/Flutter) layer not have any effect? If it's a crash from the upper (JS/Flutter) layer, wouldn't it have the scope set already?

The thought is that the code that will crash runs on the same thread/sequentially to changing scope. Imagine:

Sentry.init(..);
Sentry.setUser(user);
crash();

With setUser returning before the asynchornous code completes, the crash most likely will not contain the user.

The .NET SDK has a ConfigureScopeAsync method, similar to what @ueman suggested.

Changing the whole API such that all scope changes is something I assume we'll never do as it also becomes very cumbersome.
I think this topic is worth a call. @marandaneto what do you think?

yes, it's already on our agenda for today :)

@ueman hold on on this one for a bit, we need to discuss the right way to do it, and yesterday we didn't have time enough to discuss this further, the decision would likely affect other SDKs like Cordova, React-native etc

@ueman we could not talk about it, we'd have a meeting about that today but I won't be able to make it, but @bruno-garcia can take the lead.
let's do other tasks before getting to this one.

We discussed hybrid SDK integrations today and a lot of the design ideas and solutions we had involved synchronously passing data between layers. The way that came up then for Flutter is to call through Dart ffi into sentry-native and have Java/Kotlin also sync to sentry-native.

For iOS we would need a C ABI to access the scope too or bundle sentry-native.

That comes with its own set of drawbacks.
On macOS for example you have to sign your application if you are using ffi.
See https://dart.dev/guides/libraries/c-interop

Also you still need to think about JavaScript interop. See https://pub.dev/packages/js
JavaScript interop is synchronus though.

Was this page helpful?
0 / 5 - 0 ratings