def _HandleKnownError(self, exc, command_path_string, flag_collection, print_error=True, orig_exc=None): """Print the error and exit for exceptions of known type. Args: exc: Exception, The exception that was raised. command_path_string: str, The '.' separated command path. flag_collection: str, The flag collection name for metrics. print_error: bool, True to print an error message, False to just exit with the given error code. orig_exc: Exception or None, The original exception for metrics purposes if the exception was converted to a new type. """ msg = u'({0}) {1}'.format(console_attr.EncodeForOutput(command_path_string), console_attr.EncodeForOutput(exc)) log.debug(msg, exc_info=sys.exc_info()) if print_error: log.error(msg) metrics_exc = orig_exc or exc metrics_exc_class = metrics_exc.__class__ error_extra_info = {'error_code': getattr(exc, 'exit_code', 1)} if isinstance(exc, exceptions.HttpException): error_extra_info['http_status_code'] = exc.payload.status_code metrics.Error(command_path_string, metrics_exc_class, flag_collection, error_extra_info=error_extra_info) if properties.VALUES.core.print_handled_tracebacks.GetBool(): raise self._Exit(exc)
def _HandleKnownError(self, exc, command_path_string, flag_collection, print_error=True, orig_exc=None): """Print the error and exit for exceptions of known type. Args: exc: Exception, The exception that was raised. command_path_string: str, The '.' separated command path. flag_collection: str, The flag collection name for metrics. print_error: bool, True to print an error message, False to just exit with the given error code. orig_exc: Exception or None, The original exception for metrics purposes if the exception was converted to a new type. """ msg = u'({0}) {1}'.format( console_attr.EncodeForOutput(command_path_string), console_attr.EncodeForOutput(exc)) log.debug(msg, exc_info=sys.exc_info()) if print_error: log.error(msg) metrics_exc = orig_exc or exc metrics_exc_class = metrics_exc.__class__ metrics.Error(command_path_string, metrics_exc_class, flag_collection) self._Exit(exc)
def error(self, message): """Overrides argparse.ArgumentParser's .error(message) method. Specifically, it avoids reprinting the program name and the string "error:". Args: message: str, The error message to print. """ self.ReportErrorMetrics(message) # No need to output help/usage text if we are in completion mode. However, # we do need to populate group/command level choices. These choices are not # loaded when there is a parser error since we do lazy loading. if '_ARGCOMPLETE' in os.environ: # pylint:disable=protected-access if self._calliope_command._sub_parser: self._calliope_command.LoadAllSubElements() else: message = console_attr.EncodeForOutput(message) log.error(u'({prog}) {message}'.format(prog=self.prog, message=message)) # multi-line message means hints already added, no need for usage. # pylint:disable=protected-access if '\n' not in message: argparse._sys.stderr.write(self._calliope_command.GetUsage()) self.exit(2)
def _HandleAllErrors(self, exc, command_path_string, flag_collection): """Handle all errors. Args: exc: Exception, The exception that was raised. command_path_string: str, The '.' separated command path. flag_collection: str, The flag collection name for metrics. Raises: exc or a core.exceptions variant that does not produce a stack trace. """ if isinstance(exc, exceptions.ExitCodeNoError): self._HandleKnownError(exc, command_path_string, flag_collection, print_error=False) elif isinstance(exc, core_exceptions.Error): self._HandleKnownError(exc, command_path_string, flag_collection, print_error=True) else: known_exc = exceptions.ConvertKnownError(exc) if known_exc: self._HandleKnownError(known_exc, command_path_string, flag_collection, print_error=True, orig_exc=exc) else: # Make sure any uncaught exceptions still make it into the log file. log.debug(console_attr.EncodeForOutput(exc), exc_info=sys.exc_info()) metrics.Error(exc) raise
def _ReportCrash(err): """Report the anonymous crash information to the Error Reporting service. Args: err: Exception, the error that caused the crash. """ stacktrace = traceback.format_exc(err) stacktrace = error_reporting_util.RemovePrivateInformationFromTraceback( stacktrace) command = properties.VALUES.metrics.command_name.Get() cid = metrics.GetCIDIfMetricsEnabled() client = _GetReportingClient() reporter = util.ErrorReporting(client) try: reporter.ReportEvent(error_message=stacktrace, service=CRASH_SERVICE, version=config.CLOUD_SDK_VERSION, project=CRASH_PROJECT, request_url=command, user=cid) except apitools_exceptions.HttpError as http_err: log.file_only_logger.error( 'Unable to report crash stacktrace:\n{0}'.format( console_attr.EncodeForOutput(http_err)))
def __init__(self, args, invalid_arg): self.invalid_arg = invalid_arg cmd = os.path.basename(args[0]) if cmd.endswith('.py'): cmd = cmd[:-3] args = [cmd] + args[1:] super(InvalidCharacterInArgException, self).__init__( u'Failed to read command line argument [{0}] because it does ' u'not appear to be valid 7-bit ASCII.\n\n' u'{1}'.format(console_attr.EncodeForOutput(self.invalid_arg), _FormatNonAsciiMarkerString(args)))
def Print(self, *msg): """Writes the given message to the output stream, and adds a newline. This method has the same output behavior as the builtin print method but respects the configured verbosity. Args: *msg: str, The messages to print. """ from googlecloudsdk.core.console import console_attr # pylint: disable=g-import-not-at-top, avoid import loop msg = (console_attr.EncodeForOutput(x, escape=False) for x in msg) message = u' '.join(msg) self.write(message + u'\n')
def HandleGcloudCrash(err): """Checks if installation error occurred, then proceeds with Error Reporting. Args: err: Exception err. """ err_string = console_attr.EncodeForOutput(err) log.file_only_logger.exception('BEGIN CRASH STACKTRACE') if _IsInstallationCorruption(err): _PrintInstallationAction(err, err_string) else: log.error(u'gcloud crashed ({0}): {1}'.format( getattr(err, 'error_name', type(err).__name__), err_string)) if not properties.VALUES.core.disable_usage_reporting.GetBool(): _ReportError(err) log.err.Print( '\nIf you would like to report this issue, please run the ' 'following command:') log.err.Print(' gcloud feedback')
def _HandleAllErrors(self, exc, command_path_string, specified_arg_names): """Handle all errors. Args: exc: Exception, The exception that was raised. command_path_string: str, The '.' separated command path. specified_arg_names: [str], The specified arg named scrubbed for metrics. Raises: exc or a core.exceptions variant that does not produce a stack trace. """ if isinstance(exc, exceptions.ExitCodeNoError): self._HandleKnownError(exc, command_path_string, specified_arg_names, print_error=False) elif isinstance(exc, core_exceptions.Error): self._HandleKnownError(exc, command_path_string, specified_arg_names, print_error=True) else: known_exc = exceptions.ConvertKnownError(exc) if known_exc: self._HandleKnownError(known_exc, command_path_string, specified_arg_names, print_error=True, orig_exc=exc) else: # Make sure any uncaught exceptions still make it into the log file. log.debug(console_attr.EncodeForOutput(exc), exc_info=sys.exc_info()) metrics.Error(command_path_string, exc.__class__, specified_arg_names, error_extra_info={'error_code': 1}) raise
def main(gcloud_cli=None): metrics.Started(START_TIME) # TODO(user): Put a real version number here metrics.Executions( 'gcloud', local_state.InstallationState.VersionForInstalledComponent('core')) if gcloud_cli is None: gcloud_cli = CreateCLI([]) try: try: gcloud_cli.Execute() except IOError as err: # We want to ignore EPIPE IOErrors. # By default, Python ignores SIGPIPE (see # http://utcc.utoronto.ca/~cks/space/blog/python/SignalExceptionSurprise). # This means that attempting to write any output to a closed pipe (e.g. in # the case of output piped to `head` or `grep -q`) will result in an # IOError, which gets reported as a gcloud crash. We don't want this # behavior, so we ignore EPIPE (it's not a real error; it's a normal thing # to occur). # Before, we restore the SIGPIPE signal handler, but that caused issues # with scripts/programs that wrapped gcloud. if err.errno != errno.EPIPE: raise except Exception as err: # pylint:disable=broad-except # We want this to be parsable by `gcloud feedback`, so we print the # stacktrace with a nice recognizable string log.file_only_logger.exception('BEGIN CRASH STACKTRACE') _PrintSuggestedAction(err, console_attr.EncodeForOutput(err)) if properties.VALUES.core.print_unhandled_tracebacks.GetBool(): # We want to see the traceback as normally handled by Python raise else: # This is the case for most non-Cloud SDK developers. They shouldn't see # the full stack trace, but just the nice "gcloud crashed" message. sys.exit(1)
def __init__(self, attr, string): self._string = console_attr.EncodeForOutput( string, encoding=attr.GetEncoding(), escape=False) self._adjust = attr.DisplayWidth(self._string) - len(self._string)
def _FormatNonAsciiMarkerString(args): r"""Format a string that will mark the first non-ASCII character it contains. Example: >>> args = ['command.py', '--foo=\xce\x94'] >>> _FormatNonAsciiMarkerString(args) == ( ... 'command.py --foo=\u0394\n' ... ' ^ invalid character' ... ) True Args: args: The arg list for the command executed Returns: unicode, a properly formatted string with two lines, the second of which indicates the non-ASCII character in the first. Raises: ValueError: if the given string is all ASCII characters """ # nonascii will be True if at least one arg contained a non-ASCII character nonascii = False # pos is the position of the first non-ASCII character in ' '.join(args) pos = 0 for arg in args: try: # idx is the index of the first non-ASCII character in arg for idx, char in enumerate(arg): char.decode('ascii') except UnicodeError: # idx will remain set, indicating the first non-ASCII character pos += idx nonascii = True break # this arg was all ASCII; add 1 for the ' ' between args pos += len(arg) + 1 if not nonascii: raise ValueError('The command line is composed entirely of ASCII ' 'characters.') # Make a string that, when printed in parallel, will point to the non-ASCII # character marker_string = ' ' * pos + _MARKER # Make sure that this will still print out nicely on an odd-sized screen align = len(marker_string) args_string = u' '.join( [console_attr.EncodeForOutput(arg) for arg in args]) width, _ = console_attr_os.GetTermSize() fill = '...' if width < len(_MARKER) + len(fill): # It's hopeless to try to wrap this and make it look nice. Preserve it in # full for logs and so on. return '\n'.join((args_string, marker_string)) # If len(args_string) < width < len(marker_string) (ex:) # # args_string = 'command BAD' # marker_string = ' ^ invalid character' # width = len('----------------') # # then the truncation can give a result like the following: # # args_string = 'command BAD' # marker_string = ' ^ invalid character' # # (This occurs when args_string is short enough to not be truncated, but # marker_string is long enough to be truncated.) # # ljust args_string to make it as long as marker_string before passing to # _TruncateToLineWidth, which will yield compatible truncations. rstrip at the # end to get rid of the new trailing spaces. formatted_args_string = _TruncateToLineWidth(args_string.ljust(align), align, width, fill=fill).rstrip() formatted_marker_string = _TruncateToLineWidth(marker_string, align, width) return u'\n'.join((formatted_args_string, formatted_marker_string))