El autor está disponible para consultoría y trabajo por contratoAgenda una llamada →
Skip to content

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 ​

PropiedadTipoPor DefectoPropósito
globalExceptionHandlerFunction?nullHandler de error global para todos los commands
globalErrorsStreamN/AStream observable de todos los errores enrutados globalmente
errorFilterDefaultErrorFilterGlobalIfNoLocalErrorFilter()Filtro de error por defecto
assertionsAlwaysThrowbooltrueAssertionErrors bypasean filtros
reportAllExceptionsboolfalseSobrescribir filtros, reportar todos los errores
detailedStackTracesbooltrueStack traces mejorados
loggingHandlerFunction?nullHandler para todas las ejecuciones de commands
reportErrorHandlerExceptionsToGlobalHandlerbooltrueReportar excepciones de handlers de error
useChainCaptureboolfalseTrazas detalladas experimentales

Ejemplo de Setup Completo ​

Aquí hay un setup típico configurando múltiples propiedades globales:

dart
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:

dart
static void Function(CommandError<dynamic> error, StackTrace stackTrace)?
  globalExceptionHandler;

Establécelo una vez en tu función main() para manejar errores globalmente:

dart
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:

dart
static Stream<CommandError<dynamic>> get globalErrors

Perfecto para monitoreo de errores reactivo, analytics, crash reporting, y notificaciones de UI globales:

dart
// 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 reportAllExceptions solo de debug
  • Usa con globalExceptionHandler para 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:

dart
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:

dart
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:

dart
static bool reportAllExceptions = false;

Por defecto: false

Patrón común:

dart
// 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:

dart
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):

dart
static void Function(CommandResult<dynamic, dynamic> result)? loggingHandler;

Por defecto: null (sin logging)

Ejemplo de Integración de Analytics ​

dart
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:

dart
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:

dart
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:

dart
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:

dart
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:

dart
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:

dart
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 ​

dart
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 ​

dart
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 ​

dart
// 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:

dart
// ✅ Solo en modo debug
Command.reportAllExceptions = kDebugMode;

❌️ No Acceder a Propiedades de CommandError ​

dart
// MAL: Solo usando el objeto de error
Command.globalExceptionHandler = (commandError, stackTrace) {
  Sentry.captureException(commandError.error, stackTrace: stackTrace);
  // ¡Falta contexto valioso!
};

Solución:

dart
// ✅ 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 ​

dart
// 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:

dart
// ✅ 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 ​

dart
// 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:

dart
// ✅ Solo deshabilitar si profiling muestra que es un cuello de botella
Command.detailedStackTraces = true; // Mantener el por defecto

Ver También ​

  • Manejo de Errores (Error Handling) — Aprende cómo errorFilterDefault y globalExceptionHandler funcionan 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

Publicado bajo la Licencia MIT. Creado por Thomas Burkhart.