Configuración Global
Propiedades estáticas que configuran el comportamiento para todos los commands en tu app. Establécelas una vez, típicamente en la función main() de tu app antes de llamar runApp().
Resumen
| Propiedad | Tipo | Por Defecto | Propósito |
|---|---|---|---|
| globalExceptionHandler | Function? | null | Handler de error global para todos los commands |
| globalErrors | Stream | N/A | Stream observable de todos los errores enrutados globalmente |
| errorFilterDefault | ErrorFilter | GlobalIfNoLocalErrorFilter() | Filtro de error por defecto |
| assertionsAlwaysThrow | bool | true | AssertionErrors bypasean filtros |
| reportAllExceptions | bool | false | Sobrescribir filtros, reportar todos los errores |
| detailedStackTraces | bool | true | Stack traces mejorados |
| loggingHandler | Function? | null | Handler para todas las ejecuciones de commands |
| reportErrorHandlerExceptionsToGlobalHandler | bool | true | Reportar excepciones de handlers de error |
| useChainCapture | bool | false | Trazas detalladas experimentales |
Ejemplo de Setup Completo
Aquí hay un setup típico configurando múltiples propiedades globales:
void main() {
// Configure global command_it settings before runApp
// 1. Global exception handler - called based on ErrorFilter configuration
Command.globalExceptionHandler = (error, stackTrace) {
debugPrint('Command error: ${error.error}');
debugPrint('Command: ${error.command}');
debugPrint('Parameter: ${error.paramData}');
// In production, send to Sentry
// Sentry.captureException(error.error, stackTrace: stackTrace);
};
// 2. Default error filter - determines error handling strategy
Command.errorFilterDefault = const GlobalIfNoLocalErrorFilter();
// 3. Logging handler - log all command executions
Command.loggingHandler = (commandName, result) {
if (kDebugMode) {
debugPrint(
'Command executed: ${result.isRunning ? "started" : "completed"}');
if (result.hasError) {
debugPrint(' Error: ${result.error}');
}
}
};
// 4. Detailed stack traces - strip framework noise (default: true)
Command.detailedStackTraces = true;
// 5. Assertions always throw - bypass error filters for assertions (default: true)
Command.assertionsAlwaysThrow = true;
// 6. Report all exceptions - ensure all errors reach global handler (for debugging)
Command.reportAllExceptions = kDebugMode;
// 7. Report error handler exceptions - if local error handler throws
Command.reportErrorHandlerExceptionsToGlobalHandler = true;
runApp(MyApp());
}globalExceptionHandler
Handler de error global llamado para todos los errores de commands:
static void Function(CommandError<dynamic> error, StackTrace stackTrace)?
globalExceptionHandler;Establécelo una vez en tu función main() para manejar errores globalmente:
void main() {
Command.globalExceptionHandler = (error, stackTrace) {
loggingService.logError(error.error, stackTrace);
Sentry.captureException(error.error, stackTrace: stackTrace);
};
runApp(MyApp());
}Cuándo se llama:
- Depende de la configuración de ErrorFilter (por defecto: cuando no existen listeners locales)
- Siempre se llama cuando
reportAllExceptions: true
Ver: Manejo de Errores (Error Handling) - Handler de Error Global para documentación completa incluyendo ejemplos de uso, detalles de contexto de error, y patrones.
globalErrors
Stream observable de todos los errores de commands enrutados al handler global:
static Stream<CommandError<dynamic>> get globalErrorsPerfecto para monitoreo de errores reactivo, analytics, crash reporting, y notificaciones de UI globales:
// Ejemplo: Toast de error global en widget raíz
class MyApp extends WatchingWidget {
@override
Widget build(BuildContext context) {
registerStreamHandler<Stream<CommandError>, CommandError>(
target: Command.globalErrors,
handler: (context, snapshot, cancel) {
if (snapshot.hasData) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error: ${snapshot.data!.error}')),
);
}
},
);
return MaterialApp(home: HomePage());
}
}Puntos clave:
- Stream de broadcast (múltiples listeners soportados)
- Emite cuando ErrorFilter enruta errores a handler global
- NO emite para
reportAllExceptionssolo de debug - Usa con
globalExceptionHandlerpara manejo de errores comprehensivo
Ver: Manejo de Errores (Error Handling) - Stream de Errores Globales para documentación completa incluyendo casos de uso, comportamiento del stream, y patrones de integración.
errorFilterDefault
ErrorFilter por defecto usado cuando no se especifica filtro individual por command:
static ErrorFilter errorFilterDefault = const GlobalIfNoLocalErrorFilter();Por defecto: GlobalIfNoLocalErrorFilter() - Enrutamiento inteligente que intenta handlers locales primero, fallback a global
Ver: Manejo de Errores (Error Handling) - Configuración Global de Errores para detalles completos sobre filtros incorporados, filtros personalizados, y configuración.
assertionsAlwaysThrow
AssertionErrors bypasean ErrorFilters y siempre se relanzan:
static bool assertionsAlwaysThrow = true;Por defecto: true (recomendado) - AssertionErrors indican errores de programación y deberían crashear inmediatamente durante desarrollo
Ver: Manejo de Errores (Error Handling) - Configuración Global de Errores para detalles completos.
reportAllExceptions
Asegura que cada error llame a globalExceptionHandler, sin importar la configuración de ErrorFilter:
static bool reportAllExceptions = false;Por defecto: false
Patrón común:
// En main.dart
Command.reportAllExceptions = kDebugMode;Cuándo usar: Debugging de manejo de errores, modo desarrollo, verificar crash reporting
Ver: Manejo de Errores (Error Handling) - Configuración Global de Errores para detalles completos sobre cómo funciona, flujo de ejecución, y evitar llamadas duplicadas.
detailedStackTraces
Limpia stack traces filtrando ruido de framework:
static bool detailedStackTraces = true;Por defecto: true (recomendado)
Qué hace: Usa el paquete stack_trace para filtrar y simplificar stack traces, removiendo frames relacionados con Zone e internos de framework
Rendimiento: Overhead mínimo. Solo deshabilita si profiling muestra que es un cuello de botella (raro)
Ver: Manejo de Errores (Error Handling) - Configuración Global de Errores para detalles completos sobre qué se filtra y ejemplos.
loggingHandler
Handler llamado para cada ejecución de command (running, éxito, error):
static void Function(CommandResult<dynamic, dynamic> result)? loggingHandler;Por defecto: null (sin logging)
Ejemplo de Integración de Analytics
void setupLoggingHandler() {
Command.loggingHandler = (commandName, result) {
// Log all command executions to analytics
// Track command started
if (result.isRunning) {
analytics.logEvent('command_started', parameters: {
'command': commandName,
'has_parameter': result.paramData != null,
});
return;
}
// Track command completed
if (result.hasData) {
analytics.logEvent('command_success', parameters: {
'command': commandName,
'has_data': result.data != null,
'parameter': result.paramData?.toString(),
});
return;
}
// Track command error
if (result.hasError) {
analytics.logEvent('command_error', parameters: {
'command': commandName,
'error_type': result.error.runtimeType.toString(),
'parameter': result.paramData?.toString(),
'had_previous_data': result.data != null,
});
}
};
}Qué Datos Están Disponibles
CommandResult<TParam, TResult> proporciona:
.isRunning- Si el command se está ejecutando actualmente.hasData- Si el command tiene datos de resultado.hasError- Si el command falló.error- El objeto de error (si hay).data- Los datos del resultado (si hay).paramData- Parámetro pasado al command
Casos de Uso
- Analytics - Trackear métricas de ejecución de commands
- Monitoreo de rendimiento - Medir tiempo de ejecución de commands
- Debugging - Log de toda la actividad de commands
- Audit trails - Registrar acciones de usuario
reportErrorHandlerExceptionsToGlobalHandler
Si un handler de error local lanza una excepción, reportarla a globalExceptionHandler:
static bool reportErrorHandlerExceptionsToGlobalHandler = true;Por defecto: true (recomendado)
Qué hace: Cuando los handlers de error lanzan, captura la excepción y la envía a globalExceptionHandler con el error original almacenado en CommandError.originalError
Por qué importa: Los handlers de error también pueden tener bugs. Esto previene que código de manejo de errores crashee tu app.
Ver: Manejo de Errores (Error Handling) - Cuando los Handlers de Error Lanzan Excepciones y Configuración Global de Errores para detalles completos y ejemplos.
useChainCapture
Experimental: Preservar stack traces a través de límites async para mostrar dónde se llamaron los commands:
static bool useChainCapture = false;Por defecto: false
Qué hace:
Cuando está habilitado, preserva el call stack desde donde se invocó el command, incluso cuando la excepción ocurre dentro de una función async. Sin esto, a menudo obtienes un "async gap" - perdiendo el contexto del stack trace que muestra qué código llamó al command.
Usa el mecanismo Chain.capture() de Dart para mantener el stack trace completo a través de límites async.
Ejemplo sin useChainCapture:
#0 ApiClient.fetch (api_client.dart:42)
#1 <async gap>Ejemplo con useChainCapture:
#0 ApiClient.fetch (api_client.dart:42)
#1 _fetchDataCommand.run (data_manager.dart:156)
#2 DataScreen.build.<anonymous> (data_screen.dart:89)
#3 ... (cadena de llamadas completa preservada)Estado: Característica experimental que puede cambiar o ser removida en versiones futuras.
No recomendado para uso en producción - puede tener implicaciones de rendimiento.
Patrones de Configuración Comunes
Modo Desarrollo
Para máxima visibilidad durante desarrollo:
void configureDevelopmentMode() {
// Development: verbose logging and error reporting
// Report ALL exceptions - even if error filters would swallow them
Command.reportAllExceptions = true;
// Detailed stack traces - strip framework noise for easier debugging
Command.detailedStackTraces = true;
// Assertions always throw - catch programming errors immediately
Command.assertionsAlwaysThrow = true;
// Log every command execution for debugging
Command.loggingHandler = (commandName, result) {
final timestamp = DateTime.now().toIso8601String();
debugPrint('[$timestamp] Command execution:');
debugPrint(' isRunning: ${result.isRunning}');
debugPrint(' hasData: ${result.hasData}');
debugPrint(' hasError: ${result.hasError}');
if (result.paramData != null) {
debugPrint(' param: ${result.paramData}');
}
if (result.hasError) {
debugPrint(' error: ${result.error}');
}
};
// Global error handler - print detailed error information
Command.globalExceptionHandler = (error, stackTrace) {
debugPrint('═══ COMMAND ERROR ═══');
debugPrint('Command: ${error.command}');
debugPrint('Error: ${error.error}');
debugPrint('Parameter: ${error.paramData}');
debugPrint('Stack trace:');
debugPrint(stackTrace.toString());
debugPrint('═══════════════════');
};
// Default filter: try local, fallback to global
Command.errorFilterDefault = const GlobalIfNoLocalErrorFilter();
}Características:
- Reportar TODOS los errores (bypasear filtros)
- Logging verbose para cada command
- Stack traces detallados
- Contexto de error comprehensivo
Modo Producción
Para producción con integración de crash reporting:
void configureProductionMode() {
// Production: crash reporting only, respect error filters
// Don't report all exceptions - respect error filters
Command.reportAllExceptions = false;
// Keep detailed stack traces for crash reports
Command.detailedStackTraces = true;
// Assertions should throw - catch critical bugs
Command.assertionsAlwaysThrow = true;
// Global error handler - send to Sentry
Command.globalExceptionHandler = (error, stackTrace) {
Sentry.captureException(
error.error,
stackTrace: stackTrace,
withScope: (scope) {
scope.setTag('command', error.commandName ?? 'unknown');
scope.setContexts('command_context', {
'parameter': error.paramData?.toString(),
'error_reaction': error.errorReaction.toString(),
});
},
);
};
// Default filter: local errors stay local, unhandled go global
Command.errorFilterDefault = const GlobalIfNoLocalErrorFilter();
// If error handler itself throws, report to global handler
Command.reportErrorHandlerExceptionsToGlobalHandler = true;
}Características:
- Respetar filtros de error (no reportar todo)
- Enviar errores a servicio de crash reporting
- Stack traces detallados para debugging de problemas de producción
- Sin logging verbose (mantener producción ligera)
Modo Testing
Para tests unitarios/de integración:
void setupTestMode() {
// Deshabilitar todos los handlers para evitar efectos secundarios en tests
Command.globalExceptionHandler = null;
Command.loggingHandler = null;
// Dejar que errores lancen naturalmente para assertions de tests
Command.reportAllExceptions = false;
Command.errorFilterDefault = const ErrorHandlerNone();
}Interacciones de Propiedades
reportAllExceptions Sobrescribe Filtros de Error
Cuando reportAllExceptions: true:
Command.reportAllExceptions = true;
Command.errorFilterDefault = const LocalErrorFilter(); // ← ¡Ignorado!Cada error aún va a globalExceptionHandler, sin importar la configuración del filtro.
assertionsAlwaysThrow Bypasea Todo
Command.assertionsAlwaysThrow = true; // Por defecto
Command.errorFilterDefault = const ErrorHandlerNone(); // ← ¡Ignorado para assertions!AssertionErrors siempre se relanzan, incluso si los filtros los silenciarían.
Reportando Excepciones de Handlers de Error
Command.reportErrorHandlerExceptionsToGlobalHandler = true;
Command.globalExceptionHandler = (error, stackTrace) {
// Recibe ambos:
// 1. Errores normales de commands
// 2. Excepciones lanzadas por handlers de error locales
if (error.originalError != null) {
// Este error vino de un handler de error con bugs
print('Handler de error lanzó: ${error.error}');
print('Error original era: ${error.originalError}');
}
};Errores Comunes
❌️ Olvidar kDebugMode para reportAllExceptions
// MAL: Siempre reportar todas las excepciones, incluso en producción
Command.reportAllExceptions = true;Problema: La app en producción envía cada error a crash reporting, creando ruido.
Solución:
// ✅ Solo en modo debug
Command.reportAllExceptions = kDebugMode;❌️ No Acceder a Propiedades de CommandError
// MAL: Solo usando el objeto de error
Command.globalExceptionHandler = (commandError, stackTrace) {
Sentry.captureException(commandError.error, stackTrace: stackTrace);
// ¡Falta contexto valioso!
};Solución:
// ✅ Usar contexto completo de CommandError con Sentry
Command.globalExceptionHandler = (commandError, stackTrace) {
Sentry.captureException(
commandError.error,
stackTrace: stackTrace,
withScope: (scope) {
scope.setTag('command', commandError.command ?? 'unknown');
scope.setContexts('command_context', {
'parameter': commandError.paramData?.toString(),
'error_reaction': commandError.errorReaction.toString(),
});
},
);
};❌️ Usar loggingHandler para Manejo de Errores
// MAL: Intentando manejar errores en logging handler
Command.loggingHandler = (result) {
if (result.hasError) {
showErrorDialog(result.error); // ¡No hagas esto!
}
};Problema: loggingHandler es para observabilidad, no manejo de errores.
Solución:
// ✅ Usa globalExceptionHandler para manejo de errores
Command.globalExceptionHandler = (error, stackTrace) {
// Maneja errores aquí
};
// ✅ Usa loggingHandler solo para métricas/analytics
Command.loggingHandler = (result) {
analytics.logEvent('command_executed', parameters: {
'has_error': result.hasError,
});
};❌️ Deshabilitar detailedStackTraces Prematuramente
// MAL: Deshabilitando sin medir
Command.detailedStackTraces = false; // "Por rendimiento"Problema: El procesamiento de stack trace tiene overhead negligible. Deshabilitarlo hace el debugging más difícil.
Solución:
// ✅ Solo deshabilitar si profiling muestra que es un cuello de botella
Command.detailedStackTraces = true; // Mantener el por defectoVer También
- Manejo de Errores (Error Handling) — Aprende cómo
errorFilterDefaultyglobalExceptionHandlerfuncionan con filtros de error, incluyendo creación de filtros personalizados - Propiedades del Command — Propiedades de nivel de instancia que pueden sobrescribir valores globales por defecto (como filtros de error por command)
- Fundamentos de Command — Empieza aquí si eres nuevo en command_it - aprende cómo crear y ejecutar commands antes de configurar globales
- Resolución de Problemas — Problemas comunes y soluciones, incluyendo problemas de configuración