-
Notifications
You must be signed in to change notification settings - Fork 41
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
Is it not possible to use data dog from flutter isolate ? #580
Comments
Yes this is limitation of the Datadog SDK at the moment, you can only use it from the main isolate at the moment. If you have a need for this, please raise it as a feature request. It's definitely doable we just haven't had any requests for the functionality. |
@fuzzybinary thank you for you reply ! |
@fuzzybinary - We need this for our impl. We've been stuck back on the 3rd party plugin but need to upgrade now due to the Apple Privacy changes. How can we request this change? For clarity - we run a single FlutterEngine with two isolates. On Android - one isolate runs within a foreground service and runs even when the UI isolate is terminated. On iOS it's similar - but the runtime model for iOS means both isolates are always running. We primarily log from one isolate (background) but that isolate is always the second isolate to be established. I'm working now to upgrade to This works fine with the older, 3rd party plugin ( |
@dballance Yes, I'll try to raise it in priority. Because Datadog acts as a singleton, you should still only configure once from your primary isolate, but I'll look into ways you can communicate with that singleton from multiple isolates. |
An update as I am working through the upgrade. Atleast on Android - as long as I call This is required to ensure we can call |
|
@fuzzybinary - finally got through this today. It seems One enhancement that would be nice - is wrapping any awaits for pending initialization into the the In my current impl to get this working, Isolate A calls This seemed to work fine on Android - but on iOS the first call to Could purely be some Swift shared resource thing, but would be nice to either return an obvious failure (throw or return a result that could be used here to understand that May not be possible - but wanted to pass it along in case it was useful. Thank you for your effort with |
Hey @dballance Thanks for all the excellent info. My guess here as to the source of your race condition is the wait on the platform channel to perform its operations for initialization. I'm not sure why Likely the way I'll approach attaching from a new isolate and / or waiting for initialization is with a separate call, as void startIsolateasync {
await Datadog.waitUntilInitialized(timeout: 1.0);
var datadog = Datadog.attachIsolate()
} This way, folks who don't immediately start all isolates don't have to perform the wait. Let me know if you have other issues, and I'll let you know when I have a cleaner interface for this. |
We've pushed into production after migrating with Know it's not ideal - but is working for us. Might still be issues in RUM or other parts of the SDK, but atleast for logging we're 🎉. 🍻 |
Cool. Thank you ! |
Under certain circumstances, Flutter can create two FlutterEngines which each have their own method channels. If this happens, we could end up in a situation where RUM and Logs were not properly attached to a MethodChannel, resulting in error messages and lost calls. We're removing the `DatadogRumPlugin` and `DatadogLogsPlugin` singletons and replacing them with instances to avoid this. Both plugins will attach to existing Datadog Logs and RUM instances during initialization if they have already been inititalized. However, this breaks our current mapper implementation. Since Datadog expects the mapper during initialization, and holds it during the life of the application, we have to move the mappers to a companion object of the `*Plugin` classes to avoid issues with multiple or disconnected `MethodChannels`. This potentially also helps us with multiple isolate tracking, but is just the first step of that. refs: #596 #580 RUM-491 RUM-4438
Hi @fuzzybinary!
Datadog version: 2.6.0 Below is the minimal source code to reproduce the issue: import 'dart:isolate';
import 'package:datadog_flutter_plugin/datadog_flutter_plugin.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
final clientToken = ''; // replace with yours
final applicationId = ''; // replace with yours
final env = ''; // replace with yours
final configuration = DatadogConfiguration(
clientToken: clientToken,
env: env,
site: DatadogSite.us5,
nativeCrashReportEnabled: false,
loggingConfiguration: DatadogLoggingConfiguration(),
rumConfiguration: DatadogRumConfiguration(
applicationId: applicationId,
),
);
await DatadogSdk.instance.initialize(configuration, TrackingConsent.granted);
runApp(const MyApp());
}
void isolateFunc(RootIsolateToken rootIsolateToken) async {
BackgroundIsolateBinaryMessenger.ensureInitialized(rootIsolateToken);
await DatadogSdk.instance.attachToExisting(
DatadogAttachConfiguration(
detectLongTasks: false,
),
);
final logConfiguration = DatadogLoggerConfiguration(
remoteLogThreshold: LogLevel.info,
networkInfoEnabled: true,
customConsoleLogFunction: null,
);
try {
final logger = DatadogSdk.instance.logs!.createLogger(logConfiguration);
logger.debug('test message from background isolate');
} catch (e, st) {
debugPrint(e.toString());
debugPrint(st.toString());
}
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
const MyHomePage({super.key});
void _checkDatadogInIsolate() {
final rootIsolateToken = RootIsolateToken.instance!;
Isolate.spawn(isolateFunc, rootIsolateToken);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
),
body: Center(
child: ElevatedButton(
onPressed: _checkDatadogInIsolate,
child: const Text('Spawn'),
),
),
);
}
}
|
Hi @RustamG , Adding official support still on my radar, but I was under the impression that I'll take a look as soon as I have a chance. |
Thank you for reply. Yep, as you can see in the example above, I have Is there any understanding on when this could be resolved? Or any ways to workaround in the meantime? |
I believe the error comes from this limitation: Unable to receive Platform Channel calls in background isolates. Currently native part calls Dart via method channel just to map the log event. |
When creating a logger from a background isolate, Flutter would throw because WidgetsFlutterBinding wasn't initialized. This is specifically because we were adding a callback handler, which is not supported from background isolates. Add checks to both logs and RUM and prevent initialization of things we know won't work from background isolates. This is not full support for background isolates but usable as a work around. refs: #580
Hey @RustamG , Yes that's the main issue -- I'm curious why @dballance didn't run into it. In reality, we should not attempt to set the callback handlers in background isolates ever. Here is a more complete fix. As it says in the PR, this still isn't full background isolate support, but usable as a workaround for simple cases. |
In my case, I'm not using A VERY high level overview is here: https://docs.flutter.dev/add-to-app/multiple-flutters#components And a very simple example is here: https://github.com/flutter/samples/tree/main/add_to_app/multiple_flutters Basically, I don't run into this issue and can use plugins from all isolates. There are a few caveats (not worth digging into those in this context, imo) but it's a fundamental difference from using Isolates for background tasks / processing (i.e. using Isolate.spawn). Our app runs in the background, both on iOS and Android. Basically, on Android, we want some Unrelated note, there is an issue I have in the our backlog where it seems DD logs quit working after some time on Android. It's likely something in this ballpark, but I hesitate to open an issue here until I can investigate our impl. |
@dballance Did you update to the newest version includes this pr? |
I have not - looks like it might resolve the unrelated note I added! We did merge 2.6.0 into staging via dependabot but I just haven't had time to look into it, as i've been out of office on paternity leave 😅. |
Will try to test in the next two weeks or so (still out part time) and let you know if it resolved our issue! |
An update - I've upgraded, still potentially having some issues where logs are not updated for some android devices. However, I haven't had a chance to dive in and try to understand why. It is planned for our next release though, so I should have a better answer soon. |
@dballance Keep me posted. If it turns out it's unrelated to background isolates (either related to multiple engines or something else entirely) let's open a separate ticket for better tracking. |
Question
By calling DatadogSdk.instance.initialize in isolate I've receive such error:
[ERROR:flutter/runtime/dart_isolate.cc(1097)] Unhandled exception:
'package:flutter/src/services/platform_channel.dart': Failed assertion: line 542 pos 7: '_binaryMessenger != null || BindingBase.debugBindingType() != null': Cannot set the method call handler before the binary messenger has been initialized. This happens when you call setMethodCallHandler() before the WidgetsFlutterBinding has been initialized. You can fix this by either calling WidgetsFlutterBinding.ensureInitialized() before this or by passing a custom BinaryMessenger instance to MethodChannel().
#0 _AssertionError._doThrowNew (dart:core-patch/errors_patch.dart:51:61)
#1 _AssertionError._throwNew (dart:core-patch/errors_patch.dart:40:5)
#2 MethodChannel.setMethodCallHandler (package:flutter/src/services/platform_channel.dart:542:7)
#3 DatadogSdkMethodChannel.initialize (package:datadog_flutter_plugin/src/datadog_sdk_method_channel.dart:56:21)
#4 DatadogSdk.initialize (package:datadog_flutter_plugin/datadog_flutter_plugin.dart:168:21)
But WidgetsFlutterBinding.ensureInitialized() can not be called in isolate...
The text was updated successfully, but these errors were encountered: