Smart Grow Logs Plugin for Flutter
Smart Grow Logs for Flutter sends encrypted logs from your app to Smart Grow Logs, with optional automatic capture of uncaught errors.
What This Plugin Is For
Use this plugin if you want to:
- send debug, info, warn, error and fatal logs from Flutter
- attach metadata such as user, session or business context
- capture uncaught Flutter errors automatically
- capture async errors launched in a guarded zone
- capture failures from secondary isolates when you wire them explicitly
Before You Start
You need:
- A Smart Grow Logs project.
- An API key.
- Your ingestion URL, for example
https://logs-api.smart-grow.app/.
Installation
Add the dependency:
dependencies:
smart_grow_logs_plugin: ^2.0.1
Then run:
flutter pub get
Quick Start
This is the recommended startup pattern for most Flutter apps:
import 'package:flutter/widgets.dart';
import 'package:smart_grow_logs_plugin/smart_grow_logs_plugin.dart';
Future<void> main() async {
SmartGrowLogs.runWithAutoCapture<void>(() async {
WidgetsFlutterBinding.ensureInitialized();
await SmartGrowLogs.initialize(
apiKey: 'sgl_your_api_key',
baseUrl: 'https://logs-api.smart-grow.app/',
autoCaptureEnabled: true,
androidAnrWatchdogEnabled: true,
androidAnrTimeoutMs: 5000,
);
runApp(const MyApp());
});
}
Why this exact order:
WidgetsFlutterBinding.ensureInitialized()andrunApp()must run in the same zone in debug mode.runWithAutoCapture()ensures uncaught async errors in that zone are reported.initialize()must be called once before sending logs.
Common Use Cases
1. Send a Simple Log
await SmartGrowLogs.instance.info('User opened settings');
2. Send a Log With Metadata
await SmartGrowLogs.instance.warn(
'Payment retry scheduled',
metadata: '{"orderId":"ORD-123","retry":2}',
userIdentifier: 'user@example.com',
sessionId: 'session-abc-123',
);
3. Capture a Caught Exception
try {
await repository.sync();
} catch (error, stackTrace) {
await SmartGrowLogs.instance.errorWithException(
'Sync failed',
error,
stackTrace: stackTrace,
metadata: '{"feature":"sync"}',
);
}
4. Send a Full Custom Log
final response = await SmartGrowLogs.instance.sendLog(
LogOptions(
level: LogLevel.error,
message: 'Checkout failed',
stackTrace: StackTrace.current.toString(),
metadata: '{"cartId":"CART-42","step":"payment"}',
userIdentifier: 'user@example.com',
sessionId: 'session-abc-123',
),
);
if (!response.success) {
debugPrint('Log failed: ${response.error}');
}
Auto-Capture
When autoCaptureEnabled is true, the plugin installs these mechanisms automatically:
FlutterError.onErrorfor framework and rendering errorsPlatformDispatcher.instance.onErrorfor uncaught main-isolate runtime errorsrunWithAutoCapture()for async errors inside the guarded zone
What Is Captured Today
All auto-captured errors are sent at fatal level.
- unhandled Flutter framework errors
- unhandled runtime errors on the main isolate
- unhandled async errors inside
runWithAutoCapture() - secondary-isolate errors when you wire them explicitly
- Android main-thread ANR watchdog when enabled
- iOS uncaught
NSExceptionreported on the next app launch
What Is Not Captured Automatically Yet
- native crash signals
- every possible failure from child isolates unless you attach them explicitly
Disable Auto-Capture
Disable it if your app already owns global error handling and you want to forward failures manually:
await SmartGrowLogs.initialize(
apiKey: 'sgl_your_api_key',
baseUrl: 'https://logs-api.smart-grow.app/',
autoCaptureEnabled: false,
);
Secondary Isolates
If your app uses Isolate.spawn, create one listener on the main isolate and pass its sendPort to child isolates.
final isolateErrorPort = SmartGrowLogs.createIsolateErrorListener(
mechanism: 'MyBackgroundIsolate',
);
await Isolate.spawn<SendPort>(
backgroundEntryPoint,
isolateErrorPort.sendPort,
onError: isolateErrorPort.sendPort,
errorsAreFatal: true,
);
void backgroundEntryPoint(SendPort errorPort) {
SmartGrowLogs.attachCurrentIsolateToAutoCapture(errorPort);
throw StateError('Background isolate failure');
}
When that listener is no longer needed:
isolateErrorPort.close();
API Essentials
Main entry points:
SmartGrowLogs.initialize(...)SmartGrowLogs.instanceSmartGrowLogs.runWithAutoCapture(...)SmartGrowLogs.createIsolateErrorListener(...)SmartGrowLogs.attachCurrentIsolateToAutoCapture(...)
Main send methods:
logDebug(...)info(...)warn(...)error(...)errorWithException(...)fatal(...)sendLog(LogOptions(...))
Response object:
success: whether the log was accepted locally for deliverylogId: server log id when successfulerror: failure message when not successful
Performance Recommendation
Logging does network work. If you do not need to wait for the result, prefer non-blocking usage:
unawaited(SmartGrowLogs.instance.info('Screen opened'));
Use await only when you need to inspect success, logId or error.
Troubleshooting
I get a zone error when starting the app
Make sure WidgetsFlutterBinding.ensureInitialized() and runApp() are both inside SmartGrowLogs.runWithAutoCapture(...).
My child isolate errors are not showing up
Make sure you:
- create the listener on the main isolate
- pass its
sendPorttoIsolate.spawn - call
attachCurrentIsolateToAutoCapture(sendPort)inside the child isolate
iOS crashes appear on the next launch
That is expected for uncaught NSException. The plugin persists a crash marker and retries delivery on the next successful startup.
Requirements
- Flutter 3.3.0+
- Dart 3.0.0+
- iOS 15.0+
- Android API 26+
License
Proprietary - Smart Dev Agency