smart_grow_logs_plugin 2.0.1
smart_grow_logs_plugin: ^2.0.1 copied to clipboard
Flutter plugin for Smart Grow Logs SDK. Secure logging with end-to-end encryption. Supports Android and iOS.
example/lib/main.dart
import 'dart:async';
import 'dart:io';
import 'dart:isolate';
import 'package:flutter/material.dart';
import 'package:smart_grow_logs_plugin/smart_grow_logs_plugin.dart';
Future<void> main() async {
await SmartGrowLogs.runWithAutoCapture<void>(() async {
WidgetsFlutterBinding.ensureInitialized();
await SmartGrowLogs.initialize(
apiKey: '',
baseUrl: '',
debug: true,
autoCaptureEnabled: true,
androidAnrWatchdogEnabled: true,
androidAnrTimeoutMs: 5000,
);
runApp(const MyApp());
});
}
void triggerSecondaryIsolateCrash(SendPort errorPort) {
SmartGrowLogs.attachCurrentIsolateToAutoCapture(errorPort);
Future<void>.delayed(const Duration(milliseconds: 50), () {
throw StateError('Demo secondary isolate error from SmartGrowLogs example');
});
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
bool isInitialized = false;
bool isLoading = false;
String? errorMessage;
List<String> logHistory = [];
RawReceivePort? isolateErrorPort;
@override
void initState() {
super.initState();
isInitialized = SmartGrowLogs.isInitialized;
isolateErrorPort = SmartGrowLogs.createIsolateErrorListener(
mechanism: 'FlutterSecondaryIsolate',
);
addToHistory('✅ SDK initialized with auto-capture enabled');
}
@override
void dispose() {
isolateErrorPort?.close();
super.dispose();
}
void addToHistory(String message) {
setState(() {
logHistory.insert(0, '[${DateTime.now().toIso8601String()}] $message');
});
}
Future<void> sendLog(LogLevel level, String message) async {
if (!isInitialized) {
addToHistory('⚠️ SDK not initialized');
return;
}
setState(() => isLoading = true);
try {
final response = await SmartGrowLogs.instance.sendLog(LogOptions(
level: level,
message: message,
metadata: '{"user_session": "abc123"}',
userIdentifier: 'test_user@example.com',
sessionId: "1234567890abcdef",
stackTrace: StackTrace.current.toString(),
));
if (response.success) {
addToHistory(
'✅ [${level.value.toUpperCase()}] Sent - ID: ${response.logId}');
} else {
print("Log sending failed with error: ${response.error}");
addToHistory(
'❌ [${level.value.toUpperCase()}] Failed: ${response.error}');
}
} catch (e) {
addToHistory('❌ [${level.value.toUpperCase()}] Error: $e');
} finally {
setState(() => isLoading = false);
}
}
Future<void> triggerFlutterFrameworkError() async {
addToHistory('⚠️ Triggering Flutter framework error in next frame');
WidgetsBinding.instance.addPostFrameCallback((_) {
throw StateError(
'Demo Flutter framework error from SmartGrowLogs example');
});
}
Future<void> triggerAsyncError() async {
addToHistory('⚠️ Triggering async runtime error');
Future<void>.delayed(const Duration(milliseconds: 50), () {
throw Exception('Demo async runtime error from SmartGrowLogs example');
});
}
Future<void> triggerFatalPlatformExit() async {
addToHistory('⚠️ Triggering fatal exit to test native crash capture');
await Future<void>.delayed(const Duration(milliseconds: 150));
exit(1);
}
Future<void> triggerSecondaryIsolateError() async {
final errorPort = isolateErrorPort;
if (errorPort == null) {
addToHistory('❌ Secondary isolate listener is not available');
return;
}
addToHistory('⚠️ Triggering secondary isolate error');
await Isolate.spawn<SendPort>(
triggerSecondaryIsolateCrash,
errorPort.sendPort,
onError: errorPort.sendPort,
errorsAreFatal: true,
);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.blue,
brightness: Brightness.light,
),
useMaterial3: true,
),
home: Scaffold(
appBar: AppBar(
title: const Text('Smart Grow Logs'),
backgroundColor: Colors.blue.shade700,
foregroundColor: Colors.white,
),
body: Column(
children: [
// Status Card
Container(
width: double.infinity,
padding: const EdgeInsets.all(16),
color: isInitialized
? Colors.green.shade100
: Colors.orange.shade100,
child: Row(
children: [
Icon(
isInitialized ? Icons.check_circle : Icons.warning,
color: isInitialized ? Colors.green : Colors.orange,
),
const SizedBox(width: 8),
Text(
isInitialized ? 'SDK Initialized' : 'Initializing...',
style: TextStyle(
fontWeight: FontWeight.bold,
color: isInitialized
? Colors.green.shade700
: Colors.orange.shade700,
),
),
if (isLoading) ...[
const Spacer(),
const SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(strokeWidth: 2),
),
],
],
),
),
// Log Level Buttons
Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Send Test Logs',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 12),
Wrap(
spacing: 8,
runSpacing: 8,
children: [
_buildLogButton(
'DEBUG',
Colors.grey,
() =>
sendLog(LogLevel.debug, 'This is a debug message'),
),
_buildLogButton(
'INFO',
Colors.blue,
() => sendLog(LogLevel.info, 'This is an info message'),
),
_buildLogButton(
'WARN',
Colors.orange,
() =>
sendLog(LogLevel.warn, 'This is a warning message'),
),
_buildLogButton(
'ERROR',
Colors.red,
() =>
sendLog(LogLevel.error, 'This is an error message'),
),
_buildLogButton(
'FATAL',
Colors.purple,
() =>
sendLog(LogLevel.fatal, 'This is a fatal message'),
),
],
),
const SizedBox(height: 20),
const Text(
'Auto-Capture Tests',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 12),
Wrap(
spacing: 8,
runSpacing: 8,
children: [
_buildLogButton(
'Flutter Error',
Colors.deepOrange,
() => unawaited(triggerFlutterFrameworkError()),
),
_buildLogButton(
'Async Error',
Colors.indigo,
() => unawaited(triggerAsyncError()),
),
_buildLogButton(
'Fatal Exit',
Colors.black87,
() => unawaited(triggerFatalPlatformExit()),
),
_buildLogButton(
'Isolate Error',
Colors.teal,
() => unawaited(triggerSecondaryIsolateError()),
),
],
),
],
),
),
const Divider(),
// Log History
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding:
const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
'Log History',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
TextButton(
onPressed: () => setState(() => logHistory.clear()),
child: const Text('Clear'),
),
],
),
),
Expanded(
child: logHistory.isEmpty
? const Center(
child: Text(
'No logs yet. Send a test log!',
style: TextStyle(color: Colors.grey),
),
)
: ListView.builder(
padding: const EdgeInsets.symmetric(horizontal: 16),
itemCount: logHistory.length,
itemBuilder: (context, index) {
final log = logHistory[index];
return Padding(
padding:
const EdgeInsets.symmetric(vertical: 4),
child: Text(
log,
style: TextStyle(
fontFamily: 'monospace',
fontSize: 12,
color: log.contains('❌')
? Colors.red
: log.contains('⚠️')
? Colors.orange
: Colors.black87,
),
),
);
},
),
),
],
),
),
],
),
),
);
}
Widget _buildLogButton(String label, Color color, VoidCallback onPressed) {
return ElevatedButton(
onPressed: isInitialized && !isLoading ? onPressed : null,
style: ElevatedButton.styleFrom(
backgroundColor: color,
foregroundColor: Colors.white,
),
child: Text(label),
);
}
}