Class: Aspera::RestErrorAnalyzer

Inherits:
Object
  • Object
show all
Includes:
Singleton
Defined in:
lib/aspera/rest_error_analyzer.rb

Overview

analyze error codes returned by REST calls and raise ruby exception

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeRestErrorAnalyzer

the singleton object is registered with application specific handlers



14
15
16
17
18
19
20
21
22
23
24
# File 'lib/aspera/rest_error_analyzer.rb', line 14

def initialize
  # list of handlers
  @error_handlers = []
  @log_file = nil
  add_handler('Type Generic') do |type, call_context|
    if !call_context[:response].code.start_with?('2')
      # add generic information
      RestErrorAnalyzer.add_error(call_context, type, "#{call_context[:request]['host']} #{call_context[:response].code} #{call_context[:response].message}")
    end
  end
end

Instance Attribute Details

#log_fileObject

Returns the value of attribute log_file.



11
12
13
# File 'lib/aspera/rest_error_analyzer.rb', line 11

def log_file
  @log_file
end

Class Method Details

.add_error(call_context, type, msg) ⇒ Object

used by handler to add an error description to list of errors for logging and tracing : collect error descriptions (create file to activate)

Parameters:

  • call_context

    a Hash containing the result call_context, provided to handler

  • type

    a string describing type of exception, for logging purpose

  • msg

    one error message to add to list



91
92
93
94
95
96
97
98
99
100
101
# File 'lib/aspera/rest_error_analyzer.rb', line 91

def add_error(call_context, type, msg)
  call_context[:messages].push(msg)
  Log.log.trace1{"Found error: #{type}: #{msg}"}
  log_file = instance.log_file
  # log error for further analysis (file must exist to activate)
  return if log_file.nil? || !File.exist?(log_file)
  File.open(log_file, 'a+') do |f|
    f.write("\n=#{type}=====\n#{call_context[:request].method} #{call_context[:request].path}\n#{call_context[:response].code}\n" \
      "#{JSON.generate(call_context[:data])}\n#{call_context[:messages].join("\n")}")
  end
end

Instance Method Details

#add_handler(name, &block) ⇒ Object

add a new error handler (done at application initialization) name is the one provided here call_context is built in method raise_on_error

Parameters:

  • name

    : name of error handler (for logs)

  • block

    : processing of response: takes two parameters: name, call_context



56
57
58
# File 'lib/aspera/rest_error_analyzer.rb', line 56

def add_handler(name, &block)
  @error_handlers.unshift({name: name, block: block})
end

#add_simple_handler(name:, always: false, path:) ⇒ Object

add a simple error handler check that key exists and is string under specified path (hash) adds other keys as secondary information

Parameters:

  • name (String)

    name of error handler (for logs)

  • always (boolean) (defaults to: false)

    if true, always add error message, even if response code is 2XX

  • path (Array)

    path to error message in response



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/aspera/rest_error_analyzer.rb', line 66

def add_simple_handler(name:, always: false, path:)
  path.freeze
  add_handler(name) do |type, call_context|
    if call_context[:data].is_a?(Hash) && (!call_context[:response].code.start_with?('2') || always)
      # Log.log.debug{"simple_handler: #{type} #{path} #{path.last}"}
      # dig and find hash containing error message
      error_struct = path.length.eql?(1) ? call_context[:data] : call_context[:data].dig(*path[0..-2])
      # Log.log.debug{"found: #{error_struct.class} #{error_struct}"}
      if error_struct.is_a?(Hash) && error_struct[path.last].is_a?(String)
        RestErrorAnalyzer.add_error(call_context, type, error_struct[path.last])
        error_struct.each do |k, v|
          next if k.eql?(path.last)
          RestErrorAnalyzer.add_error(call_context, "#{type}(sub)", "#{k}: #{v}") if [String, Integer].include?(v.class)
        end
      end
    end
  end
end

#raise_on_error(req, res) ⇒ Object

Use this method to analyze a EST result and raise an exception Analyzes REST call response and raises a RestCallError exception if HTTP result code is not 2XX

Raises:



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/aspera/rest_error_analyzer.rb', line 29

def raise_on_error(req, res)
  Log.log.debug{"raise_on_error #{req.method} #{req.path} #{res[:http].code}"}
  call_context = {
    messages: [],
    request:  req,
    response: res[:http],
    data:     res[:data]
  }
  # multiple error messages can be found
  # analyze errors from provided handlers
  # note that there can be an error even if code is 2XX
  @error_handlers.each do |handler|
    begin # rubocop:disable Style/RedundantBegin
      # Log.log.debug{"test exception: #{handler[:name]}"}
      handler[:block].call(handler[:name], call_context)
    rescue StandardError => e
      Log.log.error{"ERROR in handler:\n#{e.message}\n#{e.backtrace}"}
    end
  end
  raise RestCallError.new(call_context[:messages].join("\n"), call_context[:request], call_context[:response]) unless call_context[:messages].empty?
end