class ChefCore::CLIUX::UI::ErrorPrinter

Constants

DEFAULT_ERROR_NO

Attributes

config[R]
exception[R]
id[R]
pastel[R]
target_host[R]
translation[R]

Public Class Methods

capture_multiple_failures(e, config) click to toggle source
# File lib/chef_core/cliux/ui/error_printer.rb, line 56
def self.capture_multiple_failures(e, config)
  e.params << config[:error_output_path] # Tell the operator where to find this info
  File.open(config[:error_output_path], "w") do |out|
    e.jobs.each do |j|
      wrapped = ChefCore::Errors::StandardErrorResolver.wrap_exception(j.exception, j.target_host)
      ep = ErrorPrinter.new(wrapper: wrapped, config: config)
      msg = ep.format_body.tr("\n", " ").gsub(/ {2,}/, " ").chomp.strip
      out.write("Host: #{j.target_host.hostname} ")
      if ep.exception.respond_to? :id
        out.write("Error: #{ep.exception.id}: ")
      else
        out.write(": ")
      end
      out.write("#{msg}\n")
    end
  end
end
dump_unexpected_error(e) click to toggle source

Use this to dump an an exception to output. useful if an error occurs in the error handling itself.

# File lib/chef_core/cliux/ui/error_printer.rb, line 86
def self.dump_unexpected_error(e)
  Terminal.output "INTERNAL ERROR"
  Terminal.output "-=" * 30
  Terminal.output "Message:"
  Terminal.output e.message if e.respond_to?(:message)
  Terminal.output "Backtrace:"
  Terminal.output e.backtrace if e.respond_to?(:backtrace)
  Terminal.output "=-" * 30
end
error_summary(e) click to toggle source
# File lib/chef_core/cliux/ui/error_printer.rb, line 185
def self.error_summary(e)
  if e.is_a? ChefCore::Error
    # By convention, all of our defined messages have a short summary on the first line.
    ChefCore::Text.errors.send(e.id).text(*e.params).split("\n").first
  elsif e.is_a? String
    e
  else
    if e.respond_to? :message
      e.message
    else
      ChefCore::Text.errors.UNKNOWN
    end
  end
end
new(wrapper: nil, config: nil, exception: nil) click to toggle source
# File lib/chef_core/cliux/ui/error_printer.rb, line 96
def initialize(wrapper: nil, config: nil, exception: nil)
  @exception = exception || wrapper.contained_exception
  @target_host = wrapper.target_host || target_host
  @command = @exception.respond_to?(:command) ? @exception.command : nil
  @pastel = Pastel.new
  @content = StringIO.new
  @config = config
  @id = if @exception.is_a? ChefCore::Error
          @exception.id
        else
          DEFAULT_ERROR_NO
        end
  @translation = ChefCore::Text::ErrorTranslation.new(id)
rescue => e
  ErrorPrinter.dump_unexpected_error(e)
  exit! 128
end
show_error(e, config) click to toggle source
# File lib/chef_core/cliux/ui/error_printer.rb, line 40
def self.show_error(e, config)
  # Name is misleading - it's unwrapping but also doing further
  # error resolution for common errors:
  unwrapped = ChefCore::Errors::StandardErrorResolver.unwrap_exception(e)
  if unwrapped.class == ChefCore::MultiJobFailure
    capture_multiple_failures(unwrapped, config)
  end
  formatter = ErrorPrinter.new(wrapper: e,
                               exception: unwrapped,
                               config: config)

  Terminal.output(formatter.format_error)
rescue => ex
  dump_unexpected_error(ex)
end
write_backtrace(e, args, config) click to toggle source
# File lib/chef_core/cliux/ui/error_printer.rb, line 74
def self.write_backtrace(e, args, config)
  formatter = ErrorPrinter.new(wrapper: e, config: config)
  out = StringIO.new
  formatter.add_backtrace_header(out, args)
  formatter.add_formatted_backtrace(out)
  formatter.save_backtrace(out, config)
rescue => ex
  dump_unexpected_error(ex)
end

Public Instance Methods

_format_single(out, exception, backtrace = nil) click to toggle source
# File lib/chef_core/cliux/ui/error_printer.rb, line 249
def _format_single(out, exception, backtrace = nil)
  out.puts "#{exception.class}: #{exception.message}"
  backtrace ||= exception.backtrace.to_a
  backtrace.each { |trace| out.puts "\t#{trace}" }
end
_unique_trace(backtrace1, backtrace2) click to toggle source
# File lib/chef_core/cliux/ui/error_printer.rb, line 255
def _unique_trace(backtrace1, backtrace2)
  i = 1
  while i <= backtrace1.size && i <= backtrace2.size
    break if backtrace1[-i] != backtrace2[-i]

    i += 1
  end
  backtrace1[0..-i]
end
add_backtrace_header(out, args) click to toggle source
# File lib/chef_core/cliux/ui/error_printer.rb, line 172
def add_backtrace_header(out, args)
  out.write("\n#{"-" * 80}\n")
  out.print("#{Time.now}: Error encountered while running the following:\n")
  out.print("  #{args.join(" ")}\n")
  out.print("Backtrace:\n")
end
add_formatted_backtrace(out) click to toggle source

mostly copied from gist.github.com/stanio/13d74294ca1868fed7fb

# File lib/chef_core/cliux/ui/error_printer.rb, line 231
def add_formatted_backtrace(out)
  _format_single(out, exception)
  current_backtrace = exception.backtrace
  cause = exception.cause
  until cause.nil?
    cause_trace = _unique_trace(cause.backtrace.to_a, current_backtrace)
    out.print "Caused by: "
    _format_single(out, cause, cause_trace)
    backtrace_length = cause.backtrace.length
    if backtrace_length > cause_trace.length
      out.print "\t... #{backtrace_length - cause_trace.length} more"
    end
    out.print "\n"
    current_backtrace = cause.backtrace
    cause = cause.cause
  end
end
format_body() click to toggle source
# File lib/chef_core/cliux/ui/error_printer.rb, line 146
def format_body
  if exception.is_a? ChefCore::Error
    format_workstation_exception
  elsif exception.is_a? Train::Error
    format_train_exception
  else
    format_other_exception
  end
end
format_decorated() click to toggle source
# File lib/chef_core/cliux/ui/error_printer.rb, line 132
def format_decorated
  @content << "\n"
  @content << format_header
  @content << "\n\n"
  @content << format_body
  @content << "\n"
  @content << format_footer
  @content << "\n"
end
format_error() click to toggle source
# File lib/chef_core/cliux/ui/error_printer.rb, line 114
def format_error
  if translation.decorations
    format_decorated
  else
    format_undecorated
  end
  @content.string
end
format_header() click to toggle source
# File lib/chef_core/cliux/ui/error_printer.rb, line 142
def format_header
  pastel.decorate(@id, :bold)
end
format_other_exception() click to toggle source
# File lib/chef_core/cliux/ui/error_printer.rb, line 216
def format_other_exception
  t.send(DEFAULT_ERROR_NO).text(exception.message)
end
format_train_exception() click to toggle source

TODO this gets moved to trainerrormapper or simply removed since

many of these issues are now handled in the RemoteTarget::ConnectionFailure
# File lib/chef_core/cliux/ui/error_printer.rb, line 207
def format_train_exception
  backend, host = formatted_host
  if host.nil?
    t.CHEFTRN002.text(exception.message)
  else
    t.CHEFTRN001.text(backend, host, exception.message)
  end
end
format_undecorated() click to toggle source
# File lib/chef_core/cliux/ui/error_printer.rb, line 123
def format_undecorated
  @content << "\n"
  @content << format_body
  if @command
    @content << "\n"
    @content << @command.usage
  end
end
format_workstation_exception() click to toggle source
# File lib/chef_core/cliux/ui/error_printer.rb, line 200
def format_workstation_exception
  params = exception.params
  t.send(@id).text(*params)
end
formatted_host() click to toggle source
# File lib/chef_core/cliux/ui/error_printer.rb, line 220
def formatted_host
  return nil if target_host.nil?

  cfg = target_host.config
  port = cfg[:port].nil? ? "" : ":#{cfg[:port]}"
  user = cfg[:user].nil? ? "" : "#{cfg[:user]}@"
  "#{user}#{target_host.hostname}#{port}"
end
save_backtrace(output, config) click to toggle source
# File lib/chef_core/cliux/ui/error_printer.rb, line 179
def save_backtrace(output, config)
  File.open(config[:stack_trace_path], "ab+") do |f|
    f.write(output.string)
  end
end
t() click to toggle source

't' is a convenience method for accessing error i18n error definitions. It also serves as a workaround to let us verify that correct text key lookups happen in unit tests.

# File lib/chef_core/cliux/ui/error_printer.rb, line 34
def t
  ChefCore::Text.errors
end