Talker

Handy toolkit for mobile app debugging. Inspired by web inspectors and customized for mobile application development. Modern solution providing comprehensive debugging environment through simple yet versatile functionality.

LoggingFlutterDartMobile DevelopmentDebugging

Library

Talker

Overview

Talker is a "high-performance error handling and logging library for Flutter/Dart" developed as a comprehensive debugging and monitoring solution for Flutter application development. With the concept of "Logs for Humans," it integrates recording and management of UI, HTTP requests, errors, and other information, providing essential features for Flutter developers including app monitoring, log history preservation, report sharing, custom logs, and colorful display customization.

Details

Talker 2025 edition has established a solid position as the definitive debugging and monitoring tool in the Flutter/Dart ecosystem. Providing a simple and intuitive API, it centralizes exception handling, log management, and error tracking within applications. It offers rich integration features with major libraries and patterns used in Flutter development, including automatic logging of HTTP requests/responses via Dio, integration with BLoC patterns, and connectivity with Riverpod. It comprehensively provides practical features that significantly improve development and debugging workflows, such as in-app log UI display, log history sharing and saving, and UI exception alert display.

Key Features

  • Comprehensive Log Management: Integrated management of UI, HTTP, error, and custom logs
  • Rich UI Display: Beautiful log display and customization through TalkerScreen
  • Automatic Integration Support: Built-in connectivity with Dio HTTP, BLoC, and Riverpod
  • Error Tracking and Reporting: Integration with Firebase Crashlytics, Sentry, and others
  • Color Customization: 8 default log types with complete custom support
  • Streaming Support: Real-time log monitoring and alert features

Pros and Cons

Pros

  • Rich integration options and community support in Flutter/Dart ecosystem
  • Efficient debugging experience and log management through intuitive and beautiful UI
  • Simplified communication debugging through native HTTP log integration with Dio
  • Automated state management logging through dedicated packages for BLoC and Riverpod
  • Professional error analysis through integration with Firebase Crashlytics and Sentry
  • High reliability and stability with 100% test coverage

Cons

  • Flutter-specific library, not usable on other platforms
  • Increased memory usage and performance impact with high-volume log output
  • Initial setup complexity due to rich customization features
  • Security risks from detailed log output in production environments
  • Need for proper management and privacy considerations for log saving/sharing features
  • Impact on app size due to many dependency libraries

Reference Pages

Code Examples

Installation and Setup (pubspec.yaml addition)

# Add Talker dependencies to pubspec.yaml
dependencies:
  flutter:
    sdk: flutter
  
  # Core Talker package
  talker: ^4.0.0
  
  # Flutter UI integration
  talker_flutter: ^4.0.0
  
  # HTTP logging (optional, if using Dio)
  talker_dio_logger: ^4.0.0
  
  # BLoC integration (optional, if using BLoC)
  talker_bloc_logger: ^4.0.0
  
  # Riverpod integration (optional, if using Riverpod)
  talker_riverpod_logger: ^4.0.0

dev_dependencies:
  flutter_test:
    sdk: flutter

# Install packages
# flutter pub get
// Initialize Talker in main.dart
import 'package:flutter/material.dart';
import 'package:talker_flutter/talker_flutter.dart';

// Define Talker instance globally
final talker = TalkerFlutter.init();

void main() {
  // Configure Flutter error handling
  FlutterError.onError = (FlutterErrorDetails details) {
    talker.handle(details.exception, details.stack);
  };
  
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Talker Demo',
      
      // Add Talker's NavigatorObserver for navigation logs
      navigatorObservers: [
        TalkerRouteObserver(talker),
      ],
      
      home: MyHomePage(),
      
      // Configure global error handler
      builder: (context, child) {
        return TalkerWrapper(
          talker: talker,
          child: child!,
        );
      },
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  @override
  void initState() {
    super.initState();
    // App startup log
    talker.info('App started successfully');
  }

  void _incrementCounter() {
    setState(() {
      _counter++;
      talker.info('Counter incremented: $_counter');
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Talker Demo'),
        actions: [
          // Button to navigate to log screen
          IconButton(
            icon: Icon(Icons.bug_report),
            onPressed: () {
              Navigator.of(context).push(
                MaterialPageRoute(
                  builder: (context) => TalkerScreen(talker: talker),
                ),
              );
            },
          ),
        ],
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
            ElevatedButton(
              onPressed: () {
                // Example of intentional error
                try {
                  throw Exception('Test exception');
                } catch (e, st) {
                  talker.handle(e, st);
                }
              },
              child: Text('Test Error'),
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

Basic Log Output

import 'package:talker/talker.dart';

// Create Talker instance
final talker = Talker();

void basicLoggingExample() {
  // Info log
  talker.info('Application started successfully');
  
  // Warning log
  talker.warning('Memory usage is getting high 🚨');
  
  // Debug log
  talker.debug('Starting user authentication process 🔍');
  
  // Success log
  talker.good('Data saving completed ✅');
  
  // Error log (simple string)
  talker.error('Network connection failed ❌');
  
  // Custom log type
  talker.log('Custom message', title: 'CUSTOM');
  
  // Log with specified level
  talker.logTyped(
    TalkerLog(
      'Important process started',
      logLevel: LogLevel.critical,
      title: 'PROCESS',
    ),
  );
  
  // Structured log (map data)
  talker.info({
    'event': 'user_login',
    'user_id': '12345',
    'timestamp': DateTime.now().toIso8601String(),
    'success': true,
  });
  
  // Multi-line log
  talker.info('''
  Detailed multi-line information:
  - User: John Doe
  - Operation: Data update
  - Result: Success
  ''');
}

// Exception and error handling
void errorHandlingExample() {
  try {
    // Some risky operation
    performRiskyOperation();
  } catch (error, stackTrace) {
    // Record error with detailed stack trace
    talker.handle(error, stackTrace, 'Error during user data processing');
  }
  
  // Conditional logging
  if (someCondition) {
    talker.warning('Condition matched: attention required');
  }
  
  // Output control based on log level
  talker.configure(
    settings: TalkerSettings(
      logLevel: LogLevel.info, // Output only info level and above
    ),
  );
}

void performRiskyOperation() {
  throw Exception('Sample exception');
}

bool someCondition = true;

HTTP Request Logging

import 'package:dio/dio.dart';
import 'package:talker_dio_logger/talker_dio_logger.dart';
import 'package:talker/talker.dart';

// Talker and Dio integration setup
void setupHttpLogging() {
  final talker = Talker();
  final dio = Dio();
  
  // Basic Dio Talker log configuration
  dio.interceptors.add(
    TalkerDioLogger(
      talker: talker,
      settings: const TalkerDioLoggerSettings(
        printRequestHeaders: true,
        printResponseHeaders: true,
        printResponseMessage: true,
      ),
    ),
  );
  
  // Advanced HTTP log configuration
  dio.interceptors.add(
    TalkerDioLogger(
      talker: talker,
      settings: TalkerDioLoggerSettings(
        // Request detail settings
        printRequestHeaders: true,
        printRequestData: true,
        printResponseHeaders: true,
        printResponseData: true,
        printResponseMessage: true,
        
        // Log color settings
        requestPen: AnsiPen()..blue(),
        responsePen: AnsiPen()..green(), 
        errorPen: AnsiPen()..red(),
        
        // Filtering settings
        requestFilter: (RequestOptions options) {
          // Exclude requests containing '/secure' path
          return !options.path.contains('/secure');
        },
        responseFilter: (Response response) {
          // Exclude 301 redirect responses
          return response.statusCode != 301;
        },
        
        // Error filter
        errorFilter: (DioException error) {
          // Log only specific error types
          return error.type != DioExceptionType.cancel;
        },
      ),
    ),
  );
}

// Actual HTTP request examples
void httpRequestExample() async {
  final dio = Dio();
  
  try {
    // GET request
    talker.info('Starting user data fetch');
    final response = await dio.get(
      'https://jsonplaceholder.typicode.com/users',
      queryParameters: {'_limit': 10},
    );
    talker.good('User data fetch completed: ${response.data.length} items');
    
    // POST request
    talker.info('Starting new post creation');
    final postResponse = await dio.post(
      'https://jsonplaceholder.typicode.com/posts',
      data: {
        'title': 'Talker Test Post',
        'body': 'This is a Talker HTTP log test',
        'userId': 1,
      },
    );
    
    if (postResponse.statusCode == 201) {
      talker.good('Post creation successful: ID=${postResponse.data['id']}');
    }
    
  } catch (e) {
    talker.error('HTTP request error: $e');
  }
}

// Custom HTTP log class
class CustomHttpLogger {
  final Talker talker;
  
  CustomHttpLogger(this.talker);
  
  void logRequest(String method, String url, Map<String, dynamic>? data) {
    talker.log(
      'HTTP $method $url${data != null ? '\nBody: $data' : ''}',
      title: 'HTTP_REQ',
    );
  }
  
  void logResponse(int statusCode, String url, dynamic data) {
    final isSuccess = statusCode >= 200 && statusCode < 300;
    
    if (isSuccess) {
      talker.good('HTTP $statusCode $url');
    } else {
      talker.error('HTTP $statusCode $url\nResponse: $data');
    }
  }
  
  void logError(String method, String url, String error) {
    talker.handle(
      Exception('HTTP $method $url failed: $error'),
      null,
      'HTTP Request Error',
    );
  }
}

// Custom HTTP logging usage example
void customHttpLoggingExample() async {
  final logger = CustomHttpLogger(talker);
  
  logger.logRequest('GET', '/api/users', null);
  
  try {
    // Execute HTTP request
    // ...
    logger.logResponse(200, '/api/users', {'count': 10});
  } catch (e) {
    logger.logError('GET', '/api/users', e.toString());
  }
}

Error Handling

import 'package:flutter/material.dart';
import 'package:talker_flutter/talker_flutter.dart';

// Comprehensive error handling configuration
class ErrorHandlingService {
  static final Talker talker = TalkerFlutter.init(
    settings: TalkerSettings(
      // Disable detailed logs in production
      enabled: true,
      useConsoleLogs: true,
      maxHistoryItems: 1000,
    ),
  );
  
  // Initialize app-wide error handling
  static void initializeErrorHandling() {
    // Flutter framework errors
    FlutterError.onError = (FlutterErrorDetails details) {
      talker.handle(
        details.exception,
        details.stack,
        'Flutter Framework Error',
      );
      
      // Send to external services (Crashlytics, etc.) in production
      if (isProduction) {
        sendToCrashlytics(details);
      }
    };
    
    // Dart async errors
    PlatformDispatcher.instance.onError = (error, stack) {
      talker.handle(error, stack, 'Dart Async Error');
      return true;
    };
    
    // Zone errors (optional)
    runZonedGuarded(
      () {
        runApp(MyApp());
      },
      (error, stack) {
        talker.handle(error, stack, 'Zone Caught Error');
      },
    );
  }
  
  // Custom exception classes
  static void handleBusinessError(String operation, Exception error) {
    talker.error('Business Error[$operation]: ${error.toString()}');
    
    // Display user-facing messages
    showErrorDialog(operation, error);
  }
  
  // Network error specific handling
  static void handleNetworkError(String endpoint, dynamic error) {
    String message = 'Network Error[$endpoint]';
    
    if (error is DioException) {
      switch (error.type) {
        case DioExceptionType.connectionTimeout:
          message += ': Connection timeout';
          break;
        case DioExceptionType.receiveTimeout:
          message += ': Receive timeout';
          break;
        case DioExceptionType.badResponse:
          message += ': Server error(${error.response?.statusCode})';
          break;
        default:
          message += ': ${error.message}';
      }
    }
    
    talker.error(message);
  }
  
  // Recoverable error handling
  static Future<T?> handleRecoverableError<T>(
    String operation,
    Future<T> Function() action,
    {int maxRetries = 3}
  ) async {
    for (int attempt = 0; attempt < maxRetries; attempt++) {
      try {
        talker.debug('Executing $operation... (attempt ${attempt + 1}/$maxRetries)');
        final result = await action();
        
        if (attempt > 0) {
          talker.good('$operation succeeded on retry (attempt ${attempt + 1})');
        }
        
        return result;
        
      } catch (error, stackTrace) {
        talker.warning('$operation failed (attempt ${attempt + 1}/$maxRetries): $error');
        
        if (attempt == maxRetries - 1) {
          talker.handle(error, stackTrace, '$operation failed on final attempt');
          rethrow;
        }
        
        // Wait with exponential backoff
        await Future.delayed(Duration(seconds: 2 << attempt));
      }
    }
    
    return null;
  }
}

// Error-specific dialog
void showErrorDialog(String operation, Exception error) {
  // Implementation depends on environment
  talker.info('Showing error dialog: $operation');
}

// External service sending (e.g., Firebase Crashlytics)
void sendToCrashlytics(FlutterErrorDetails details) {
  // Actual implementation would send to Firebase Crashlytics
  talker.info('Sending error to Crashlytics: ${details.exception}');
}

bool get isProduction => const bool.fromEnvironment('dart.vm.product');

// Usage examples
void errorHandlingUsageExample() async {
  // Basic error handling
  try {
    await riskyOperation();
  } catch (e, st) {
    ErrorHandlingService.talker.handle(e, st, 'Error in risky operation');
  }
  
  // Business error handling
  try {
    validateUserInput('');
  } on ValidationException catch (e) {
    ErrorHandlingService.handleBusinessError('User input validation', e);
  }
  
  // Recoverable error handling
  final result = await ErrorHandlingService.handleRecoverableError(
    'Data sync',
    () => syncDataFromServer(),
    maxRetries: 5,
  );
  
  if (result != null) {
    ErrorHandlingService.talker.good('Data sync completed');
  }
}

Future<void> riskyOperation() async {
  throw Exception('Something went wrong');
}

void validateUserInput(String input) {
  if (input.isEmpty) {
    throw ValidationException('Input is empty');
  }
}

Future<String> syncDataFromServer() async {
  // Data sync from server (may fail)
  if (DateTime.now().millisecond % 3 == 0) {
    throw Exception('Server connection error');
  }
  return 'Data sync completed';
}

class ValidationException implements Exception {
  final String message;
  ValidationException(this.message);
  
  @override
  String toString() => 'ValidationException: $message';
}

UI Integration (TalkerScreen)

import 'package:flutter/material.dart';
import 'package:talker_flutter/talker_flutter.dart';

// Customized TalkerScreen implementation
class CustomTalkerScreen extends StatefulWidget {
  final Talker talker;
  
  const CustomTalkerScreen({Key? key, required this.talker}) : super(key: key);
  
  @override
  State<CustomTalkerScreen> createState() => _CustomTalkerScreenState();
}

class _CustomTalkerScreenState extends State<CustomTalkerScreen> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('App Logs'),
        backgroundColor: Colors.blueGrey[800],
        foregroundColor: Colors.white,
        actions: [
          // Log clear button
          IconButton(
            icon: const Icon(Icons.clear_all),
            onPressed: () {
              showDialog(
                context: context,
                builder: (context) => AlertDialog(
                  title: const Text('Clear Logs'),
                  content: const Text('Delete all logs?'),
                  actions: [
                    TextButton(
                      onPressed: () => Navigator.pop(context),
                      child: const Text('Cancel'),
                    ),
                    TextButton(
                      onPressed: () {
                        widget.talker.cleanHistory();
                        Navigator.pop(context);
                        widget.talker.info('Log history cleared');
                      },
                      child: const Text('Delete'),
                    ),
                  ],
                ),
              );
            },
          ),
          // Log share button
          IconButton(
            icon: const Icon(Icons.share),
            onPressed: () => _shareLogHistory(),
          ),
          // Settings button
          IconButton(
            icon: const Icon(Icons.settings),
            onPressed: () => _showLogSettings(),
          ),
        ],
      ),
      body: TalkerScreen(
        talker: widget.talker,
        // Apply custom theme
        theme: TalkerScreenTheme(
          backgroundColor: Colors.grey[900]!,
          cardColor: Colors.grey[800]!,
          textColor: Colors.white,
          logColors: {
            // HTTP request/response colors
            TalkerLogType.httpRequest.key: Colors.blue[300]!,
            TalkerLogType.httpResponse.key: Colors.green[300]!,
            
            // Error level color settings
            TalkerLogType.error.key: Colors.red[400]!,
            TalkerLogType.critical.key: Colors.red[600]!,
            TalkerLogType.warning.key: Colors.orange[400]!,
            TalkerLogType.info.key: Colors.blue[200]!,
            TalkerLogType.debug.key: Colors.grey[400]!,
            TalkerLogType.verbose.key: Colors.grey[600]!,
            
            // Custom log type colors
            'CUSTOM': Colors.purple[300]!,
            'BUSINESS': Colors.teal[300]!,
            'PERFORMANCE': Colors.yellow[300]!,
          },
        ),
        // Custom builder for log items
        itemsBuilder: (context, data) {
          return TalkerDataCards(
            data: data,
            onCopyTap: (text) {
              _copyToClipboard(text);
              ScaffoldMessenger.of(context).showSnackBar(
                const SnackBar(content: Text('Log copied to clipboard')),
              );
            },
          );
        },
      ),
      
      // Floating action button to add test logs
      floatingActionButton: FloatingActionButton.extended(
        onPressed: _addTestLogs,
        icon: const Icon(Icons.add),
        label: const Text('Test Logs'),
      ),
    );
  }
  
  void _shareLogHistory() {
    final logs = widget.talker.history.formatted;
    
    // Actual implementation would use share_plus package, etc.
    widget.talker.info('Sharing log history (${logs.length} lines)');
    
    // Simulation: actual implementation would share files or send emails
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text('Share Logs'),
        content: Text('${logs.length} lines of logs prepared for sharing'),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: const Text('OK'),
          ),
        ],
      ),
    );
  }
  
  void _showLogSettings() {
    showModalBottomSheet(
      context: context,
      builder: (context) => Container(
        padding: const EdgeInsets.all(16),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            const Text(
              'Log Settings',
              style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 16),
            ListTile(
              title: const Text('Log Level'),
              subtitle: const Text('Minimum level of logs to display'),
              trailing: DropdownButton<LogLevel>(
                value: LogLevel.verbose,
                items: LogLevel.values.map((level) {
                  return DropdownMenuItem(
                    value: level,
                    child: Text(level.name),
                  );
                }).toList(),
                onChanged: (level) {
                  if (level != null) {
                    widget.talker.configure(
                      settings: TalkerSettings(logLevel: level),
                    );
                    Navigator.pop(context);
                  }
                },
              ),
            ),
            ListTile(
              title: const Text('History Size'),
              subtitle: const Text('Maximum number of logs to retain'),
              trailing: const Text('1000 items'),
              onTap: () {
                // History size setting dialog
                Navigator.pop(context);
              },
            ),
          ],
        ),
      ),
    );
  }
  
  void _copyToClipboard(String text) {
    // Actual implementation would use Clipboard.setData()
    widget.talker.debug('Copied to clipboard: ${text.substring(0, 50)}...');
  }
  
  void _addTestLogs() {
    widget.talker.info('Adding test logs');
    widget.talker.warning('This is a warning message');
    widget.talker.error('This is an error message');
    widget.talker.good('This is a success message');
    widget.talker.debug('This is a debug message');
    
    // Custom log
    widget.talker.log(
      'Custom business logic log',
      title: 'BUSINESS',
    );
    
    // Structured data
    widget.talker.info({
      'event': 'test_log_added',
      'timestamp': DateTime.now().toIso8601String(),
      'data': {'count': 5, 'type': 'sample'}
    });
  }
}

// TalkerScreen embedding example (integration into other screens)
class DebugDrawer extends StatelessWidget {
  final Talker talker;
  
  const DebugDrawer({Key? key, required this.talker}) : super(key: key);
  
  @override
  Widget build(BuildContext context) {
    return Drawer(
      child: Column(
        children: [
          DrawerHeader(
            decoration: BoxDecoration(
              color: Colors.blue[600],
            ),
            child: const Text(
              'Debug Menu',
              style: TextStyle(color: Colors.white, fontSize: 20),
            ),
          ),
          Expanded(
            child: TalkerScreen(
              talker: talker,
              theme: const TalkerScreenTheme(
                backgroundColor: Colors.white,
                cardColor: Color(0xFFF5F5F5),
                textColor: Colors.black87,
              ),
            ),
          ),
          Container(
            padding: const EdgeInsets.all(8),
            child: Row(
              children: [
                Expanded(
                  child: ElevatedButton(
                    onPressed: () => talker.cleanHistory(),
                    child: const Text('Clear Logs'),
                  ),
                ),
                const SizedBox(width: 8),
                Expanded(
                  child: ElevatedButton(
                    onPressed: () {
                      Navigator.push(
                        context,
                        MaterialPageRoute(
                          builder: (context) => CustomTalkerScreen(talker: talker),
                        ),
                      );
                    },
                    child: const Text('Detail View'),
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

// Main screen TalkerScreen integration example
class MainScreenWithTalker extends StatelessWidget {
  final Talker talker;
  
  const MainScreenWithTalker({Key? key, required this.talker}) : super(key: key);
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Main App'),
        actions: [
          // Show log button only in debug mode
          if (!const bool.fromEnvironment('dart.vm.product'))
            IconButton(
              icon: Stack(
                children: [
                  const Icon(Icons.bug_report),
                  // Error count badge
                  TalkerBuilder(
                    talker: talker,
                    builder: (context, data) {
                      final errorCount = data
                          .where((log) => log.logLevel.index >= LogLevel.error.index)
                          .length;
                      
                      if (errorCount > 0) {
                        return Positioned(
                          right: 0,
                          top: 0,
                          child: Container(
                            padding: const EdgeInsets.all(2),
                            decoration: const BoxDecoration(
                              color: Colors.red,
                              shape: BoxShape.circle,
                            ),
                            child: Text(
                              '$errorCount',
                              style: const TextStyle(
                                color: Colors.white,
                                fontSize: 10,
                              ),
                            ),
                          ),
                        );
                      }
                      return const SizedBox.shrink();
                    },
                  ),
                ],
              ),
              onPressed: () {
                Navigator.push(
                  context,
                  MaterialPageRoute(
                    builder: (context) => CustomTalkerScreen(talker: talker),
                  ),
                );
              },
            ),
        ],
      ),
      
      // Debug drawer
      endDrawer: !const bool.fromEnvironment('dart.vm.product')
          ? DebugDrawer(talker: talker)
          : null,
      
      body: const Center(
        child: Text('Main Content'),
      ),
    );
  }
}

Custom Log Configuration

import 'package:talker/talker.dart';
import 'package:talker_flutter/talker_flutter.dart';

// Custom log type definitions
class BusinessLog extends TalkerLog {
  BusinessLog(String message) : super(message);
  
  @override
  String get key => 'BUSINESS';
  
  @override
  String get title => 'Business Logic';
  
  @override
  AnsiPen get pen => AnsiPen()..magenta();
}

class PerformanceLog extends TalkerLog {
  final int duration;
  final String operation;
  
  PerformanceLog(this.operation, this.duration) 
      : super('$operation execution time: ${duration}ms');
  
  @override
  String get key => 'PERFORMANCE';
  
  @override
  String get title => 'Performance';
  
  @override
  AnsiPen get pen => AnsiPen()..yellow();
}

class SecurityLog extends TalkerLog {
  final String userId;
  final String action;
  
  SecurityLog(this.action, {required this.userId}) 
      : super('Security event: $action [User: $userId]');
  
  @override
  String get key => 'SECURITY';
  
  @override
  String get title => 'Security';
  
  @override
  AnsiPen get pen => AnsiPen()..red();
}

// Custom Talker configuration class
class AppTalkerConfig {
  static Talker createTalker() {
    return TalkerFlutter.init(
      settings: TalkerSettings(
        // Basic settings
        enabled: true,
        useConsoleLogs: true,
        useHistory: true,
        maxHistoryItems: 1000,
        
        // Log level settings (adjust for production)
        logLevel: _getLogLevel(),
        
        // Log formatter
        loggerFormatter: CustomLogFormatter(),
        
        // Log filter
        loggerFilter: CustomLogFilter(),
      ),
      
      // Register custom log types
      logger: TalkerLogger(
        settings: TalkerLoggerSettings(
          enableColors: true,
          lineLength: 120,
        ),
      ),
    );
  }
  
  static LogLevel _getLogLevel() {
    // Environment-based log level configuration
    if (const bool.fromEnvironment('dart.vm.product')) {
      return LogLevel.warning; // Production: warning and above only
    } else if (const bool.fromEnvironment('dart.vm.profile')) {
      return LogLevel.info; // Profile: info and above
    } else {
      return LogLevel.verbose; // Debug: everything
    }
  }
}

// Custom log formatter
class CustomLogFormatter implements LoggerFormatter {
  @override
  String fmt(LogDetails details, TalkerLoggerSettings settings) {
    final time = DateTime.now().toString().substring(11, 23);
    final level = details.logLevel.name.toUpperCase().padRight(7);
    final title = details.title?.padRight(10) ?? ''.padRight(10);
    
    return '[$time] [$level] [$title] ${details.message}';
  }
}

// Custom log filter
class CustomLogFilter implements LoggerFilter {
  // Keywords to filter
  static const List<String> _sensitiveKeywords = [
    'password',
    'token',
    'secret',
    'key',
    'credential',
  ];
  
  @override
  bool shouldLog(LogDetails details) {
    final message = details.message.toString().toLowerCase();
    
    // Exclude logs containing sensitive information
    if (_sensitiveKeywords.any((keyword) => message.contains(keyword))) {
      return false;
    }
    
    // Exclude specific log types in production
    if (const bool.fromEnvironment('dart.vm.product')) {
      if (details.title == 'DEBUG' || details.title == 'VERBOSE') {
        return false;
      }
    }
    
    return true;
  }
}

// Performance measurement with logging
class PerformanceLogger {
  final Talker talker;
  final Map<String, DateTime> _startTimes = {};
  
  PerformanceLogger(this.talker);
  
  void startOperation(String operationName) {
    _startTimes[operationName] = DateTime.now();
    talker.debug('Performance measurement started: $operationName');
  }
  
  void endOperation(String operationName) {
    final startTime = _startTimes.remove(operationName);
    if (startTime != null) {
      final duration = DateTime.now().difference(startTime).inMilliseconds;
      talker.logTyped(PerformanceLog(operationName, duration));
      
      // Warning for slow operations
      if (duration > 1000) {
        talker.warning('Slow operation detected: $operationName (${duration}ms)');
      }
    }
  }
  
  Future<T> measureAsync<T>(
    String operationName,
    Future<T> Function() operation,
  ) async {
    startOperation(operationName);
    try {
      final result = await operation();
      endOperation(operationName);
      return result;
    } catch (e) {
      endOperation(operationName);
      rethrow;
    }
  }
}

// Usage examples and setup
void customLoggingExample() {
  // Create custom Talker
  final talker = AppTalkerConfig.createTalker();
  
  // Create performance logger
  final perfLogger = PerformanceLogger(talker);
  
  // Custom log usage examples
  talker.logTyped(BusinessLog('Starting user authentication process'));
  talker.logTyped(SecurityLog('Login attempt', userId: 'user123'));
  
  // Performance measurement example
  perfLogger.startOperation('Database query');
  
  // Some processing...
  Future.delayed(Duration(milliseconds: 500), () {
    perfLogger.endOperation('Database query');
  });
  
  // Async process measurement
  perfLogger.measureAsync('File reading', () async {
    await Future.delayed(Duration(milliseconds: 200));
    return 'File data';
  });
  
  // Structured log example
  talker.info({
    'event': 'user_action',
    'user_id': 'user123',
    'action': 'purchase',
    'item_id': 'item456',
    'amount': 1200,
    'timestamp': DateTime.now().toIso8601String(),
    'metadata': {
      'platform': 'mobile',
      'version': '1.2.3',
    },
  });
  
  // Log level usage examples
  talker.verbose('Detailed debug information');
  talker.debug('Debug information');
  talker.info('General information');
  talker.warning('Attention required situation');
  talker.error('Error occurred');
  
  // Custom title log
  talker.log('Custom message', title: 'CUSTOM');
  
  // Conditional logging
  if (shouldLogDetailedInfo()) {
    talker.debug('Detailed info: Database connection pool usage 85%');
  }
  
  // Real-time log monitoring example
  talker.stream.listen((log) {
    if (log.logLevel.index >= LogLevel.error.index) {
      // Send error level and above logs to external service
      sendToExternalService(log);
    }
  });
}

bool shouldLogDetailedInfo() {
  // Enable detailed logs in debug mode or specific conditions
  return !const bool.fromEnvironment('dart.vm.product');
}

void sendToExternalService(TalkerDataInterface log) {
  // Send to external log aggregation services (Splunk, ELK, Datadog, etc.)
  print('Sending log to external service: ${log.message}');
}