# frozen_string_literal: true require "securerandom" require "json" module MinatoErrorHandler module Errors class MinatoError < StandardError attr_accessor :caused_by, :details, :debug_details attr_reader :http_request, :http_response def message raise_method_not_implemented_error __method__ end def error_reporting_type "type.googleapis.com/google.devtools.clouderrorreporting.v1beta1.ReportedErrorEvent" end def status_code raise_method_not_implemented_error __method__ end def code self.class.name end def backtrace=(backtrace) set_backtrace(backtrace) end def unique_identifier @unique_identifier ||= SecureRandom.uuid[0, 8] end def to_json(*_args) serialized_hash(serializable_methods_to_log).to_json end def as_json serialized_hash(serializable_methods_to_log).as_json end def json_response serialized_hash(serializable_methods_to_response).as_json end def http_request=(req) return if req.nil? @http_request = { headers: parse_http_request_headers(req.headers), host: req.host, method: req.request_method, path: req.path, query: req.query_parameters, remote: req.remote_ip, scheme: req.scheme } end def http_response=(res) return if res.nil? @http_response = { headers: parse_http_response_headers(res.headers), status: res.status, text_status: res.status_message } end def stack_trace backtrace end private def serializable_methods_to_log %i[caused_by code details debug_details message http_request http_response status_code unique_identifier stack_trace @type] end def serializable_methods_to_response methods_to_exclude = %i[http_request http_response stack_trace debug_details] serializable_methods_to_log.reject { |m| methods_to_exclude.include? m } end def serialized_hash(methods) data = {} methods.each do |method| if method == :@type data["@type"] = error_reporting_type else data[method] = send(method) end end data end def parse_http_request_headers(headers) selected_headers = headers.env.filter { |k, _v| k.upcase.start_with? "HTTP" } selected_headers.transform_keys! { |k| k.gsub(/\bHTTP_/, "").downcase } selected_headers end def parse_http_response_headers(headers) headers.transform_keys(&:downcase) end def raise_method_not_implemented_error(method_name) raise "You must define \"#{method_name}\" in your concrete class." end end end end