flex_logger_isolate 1.0.0
flex_logger_isolate: ^1.0.0 copied to clipboard
Isolate logging integration for FlexLogger - enables logging from Dart isolates to the main isolate logger.
example/lib/main.dart
import 'dart:async';
import 'dart:isolate';
import 'dart:math';
import 'package:flex_logger/flex_logger.dart';
import 'package:flex_logger_console/flex_logger_console.dart';
import 'package:flex_logger_isolate/flex_logger_isolate.dart';
import 'package:flutter/material.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
FlexLogger.instance.configure(
providers: [
ConsoleLoggerProvider(),
IsolateLoggerProvider(),
],
);
await FlexLogger.instance.initialize();
FlexLogger.instance.info('Application started with isolate logging support');
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
void dispose() {
FlexLogger.instance.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'FlexLogger Isolate Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
final List<String> _activeIsolates = [];
bool _isProcessing = false;
void _updateActiveIsolates() {
setState(() {
_activeIsolates.clear();
final provider = FlexLogger.instance.getProvider<IsolateLoggerProvider>();
if (provider != null) {
_activeIsolates.addAll(provider.activeIsolateIds);
}
});
}
/// Run two workers concurrently: worker-1 and worker-2
Future<void> _runTwoWorkers() async {
FlexLogger.instance.info('Starting two worker isolates');
setState(() {
_isProcessing = true;
});
final sendPort1 = FlexLogger.instance.initializeIsolate('worker-1');
final sendPort2 = FlexLogger.instance.initializeIsolate('worker-2');
_updateActiveIsolates();
await Future.wait([
Isolate.spawn(_worker1EntryPoint, sendPort1),
Isolate.spawn(_worker2EntryPoint, sendPort2),
]);
// Give workers time to finish (Isolate.spawn completes when spawned, not when isolate exits)
await Future<void>.delayed(const Duration(seconds: 5));
FlexLogger.instance.disposeIsolate('worker-1');
FlexLogger.instance.disposeIsolate('worker-2');
_updateActiveIsolates();
FlexLogger.instance.success('Both workers completed');
setState(() {
_isProcessing = false;
});
}
/// Test main thread logging
void _testMainThreadLogs() {
FlexLogger.instance.debug('Debug from main thread');
FlexLogger.instance.info('Info from main thread');
FlexLogger.instance.success('Success from main thread');
FlexLogger.instance.warning('Warning from main thread');
FlexLogger.instance.error('Error from main thread');
FlexLogger.instance.critical('Critical from main thread');
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: const Text('FlexLogger + Isolate Demo'),
),
body: Column(
children: [
Container(
width: double.infinity,
padding: const EdgeInsets.all(12),
color: Colors.purple.shade50,
child: const Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(Icons.info_outline, size: 16),
SizedBox(width: 8),
Text(
'Isolate Logging Demo',
style: TextStyle(fontWeight: FontWeight.bold),
),
],
),
SizedBox(height: 4),
Text(
'Logs from isolates are forwarded to FlexLogger.instance and displayed in console',
style: TextStyle(fontSize: 12),
),
],
),
),
Container(
width: double.infinity,
padding: const EdgeInsets.all(16),
color: Colors.blue.shade50,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Active Isolates: ${_activeIsolates.length}',
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
if (_activeIsolates.isNotEmpty) ...[
const SizedBox(height: 8),
Wrap(
spacing: 8,
children: _activeIsolates
.map(
(id) => Chip(
label: Text(id),
avatar: const CircleAvatar(
backgroundColor: Colors.green,
child: Icon(Icons.play_arrow, size: 16, color: Colors.white),
),
),
)
.toList(),
),
],
],
),
),
Expanded(
child: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Text(
'Main Thread Logging:',
style: TextStyle(fontWeight: FontWeight.w600, fontSize: 16),
),
const SizedBox(height: 8),
ElevatedButton.icon(
onPressed: _testMainThreadLogs,
icon: const Icon(Icons.playlist_add_check),
label: const Text('Test All Log Levels (Main Thread)'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue.shade100,
),
),
const SizedBox(height: 24),
const Divider(),
const SizedBox(height: 16),
const Text(
'Isolate Logging:',
style: TextStyle(fontWeight: FontWeight.w600, fontSize: 16),
),
const SizedBox(height: 8),
ElevatedButton.icon(
onPressed: _isProcessing ? null : _runTwoWorkers,
icon: const Icon(Icons.group_work),
label: const Text('Run worker-1 and worker-2'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.green.shade100,
),
),
const SizedBox(height: 24),
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.grey.shade100,
borderRadius: BorderRadius.circular(8),
),
child: const Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Check your console/terminal for logs!',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14,
),
),
SizedBox(height: 8),
Text(
'Logs from both main thread and isolates will appear '
'in the console with their respective keys (worker-1, worker-2).',
style: TextStyle(fontSize: 12),
),
],
),
),
],
),
),
),
if (_isProcessing)
Container(
padding: const EdgeInsets.all(16),
color: Colors.orange.shade50,
child: const Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(strokeWidth: 2),
),
SizedBox(width: 12),
Text('Workers are running...'),
],
),
),
],
),
);
}
}
// ============================================================================
// Isolate Entry Points
// ============================================================================
void _worker1EntryPoint(SendPort sendPort) {
final logger = IsolateLogger(
tag: 'worker-1',
sendPort: sendPort,
);
logger.info('Worker-1 started');
logger.debug('Worker-1: Initializing...');
for (int i = 1; i <= 3; i++) {
logger.debug('Worker-1: Processing step $i/3');
final sum = List.generate(50000 * i, (i) => i).reduce((a, b) => a + b);
logger.info('Worker-1: Step $i completed (sum: $sum)');
}
logger.success('Worker-1 finished successfully');
}
void _worker2EntryPoint(SendPort sendPort) {
final logger = IsolateLogger(
tag: 'worker-2',
sendPort: sendPort,
);
logger.info('Worker-2 started');
logger.debug('Worker-2: Starting heavy computation...');
final random = Random();
var total = 0;
const iterations = 500000;
for (int i = 0; i < iterations; i++) {
total += random.nextInt(100);
if (i == iterations ~/ 4) {
logger.debug('Worker-2: 25% complete');
} else if (i == iterations ~/ 2) {
logger.info('Worker-2: 50% complete');
} else if (i == (iterations * 3) ~/ 4) {
logger.debug('Worker-2: 75% complete');
}
}
logger.success('Worker-2 finished with total: $total');
}