dumpErrorToConsole method

void dumpErrorToConsole (FlutterErrorDetails details, { bool forceReport: false })

Prints the given exception details to the console.

The first time this is called, it dumps a very verbose message to the console using debugPrint.

Subsequent calls only dump the first line of the exception, unless forceReport is set to true (in which case it dumps the verbose message).

Call resetErrorCount to cause this method to go back to acting as if it had not been called before (so the next message is verbose again).

The default behavior for the onError handler is to call this function.

Implementation

static void dumpErrorToConsole(FlutterErrorDetails details, { bool forceReport = false }) {
  assert(details != null);
  assert(details.exception != null);
  bool reportError = details.silent != true; // could be null
  assert(() {
    // In checked mode, we ignore the "silent" flag.
    reportError = true;
    return true;
  }());
  if (!reportError && !forceReport)
    return;
  if (_errorCount == 0 || forceReport) {
    final String header = '\u2550\u2550\u2561 EXCEPTION CAUGHT BY ${details.library} \u255E'.toUpperCase();
    final String footer = '\u2550' * wrapWidth;
    debugPrint('$header${"\u2550" * (footer.length - header.length)}');
    final String verb = 'thrown${ details.context != null ? " ${details.context}" : ""}';
    if (details.exception is NullThrownError) {
      debugPrint('The null value was $verb.', wrapWidth: wrapWidth);
    } else if (details.exception is num) {
      debugPrint('The number ${details.exception} was $verb.', wrapWidth: wrapWidth);
    } else {
      String errorName;
      if (details.exception is AssertionError) {
        errorName = 'assertion';
      } else if (details.exception is String) {
        errorName = 'message';
      } else if (details.exception is Error || details.exception is Exception) {
        errorName = '${details.exception.runtimeType}';
      } else {
        errorName = '${details.exception.runtimeType} object';
      }
      // Many exception classes put their type at the head of their message.
      // This is redundant with the way we display exceptions, so attempt to
      // strip out that header when we see it.
      final String prefix = '${details.exception.runtimeType}: ';
      String message = details.exceptionAsString();
      if (message.startsWith(prefix))
        message = message.substring(prefix.length);
      debugPrint('The following $errorName was $verb:\n$message', wrapWidth: wrapWidth);
    }
    Iterable<String> stackLines = (details.stack != null) ? details.stack.toString().trimRight().split('\n') : null;
    if ((details.exception is AssertionError) && (details.exception is! FlutterError)) {
      bool ourFault = true;
      if (stackLines != null) {
        final List<String> stackList = stackLines.take(2).toList();
        if (stackList.length >= 2) {
          // TODO(ianh): This has bitrotted and is no longer matching. https://github.com/flutter/flutter/issues/4021
          final RegExp throwPattern = RegExp(r'^#0 +_AssertionError._throwNew \(dart:.+\)$');
          final RegExp assertPattern = RegExp(r'^#1 +[^(]+ \((.+?):([0-9]+)(?::[0-9]+)?\)$');
          if (throwPattern.hasMatch(stackList[0])) {
            final Match assertMatch = assertPattern.firstMatch(stackList[1]);
            if (assertMatch != null) {
              assert(assertMatch.groupCount == 2);
              final RegExp ourLibraryPattern = RegExp(r'^package:flutter/');
              ourFault = ourLibraryPattern.hasMatch(assertMatch.group(1));
            }
          }
        }
      }
      if (ourFault) {
        debugPrint('\nEither the assertion indicates an error in the framework itself, or we should '
                   'provide substantially more information in this error message to help you determine '
                   'and fix the underlying cause.', wrapWidth: wrapWidth);
        debugPrint('In either case, please report this assertion by filing a bug on GitHub:', wrapWidth: wrapWidth);
        debugPrint('  https://github.com/flutter/flutter/issues/new?template=BUG.md');
      }
    }
    if (details.stack != null) {
      debugPrint('\nWhen the exception was thrown, this was the stack:', wrapWidth: wrapWidth);
      if (details.stackFilter != null) {
        stackLines = details.stackFilter(stackLines);
      } else {
        stackLines = defaultStackFilter(stackLines);
      }
      for (String line in stackLines)
        debugPrint(line, wrapWidth: wrapWidth);
    }
    if (details.informationCollector != null) {
      final StringBuffer information = StringBuffer();
      details.informationCollector(information);
      debugPrint('\n${information.toString().trimRight()}', wrapWidth: wrapWidth);
    }
    debugPrint(footer);
  } else {
    debugPrint('Another exception was thrown: ${details.exceptionAsString().split("\n")[0].trimLeft()}');
  }
  _errorCount += 1;
}