# Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details. # frozen_string_literal: true require 'contrast/agent/telemetry/events/exceptions/telemetry_exceptions' require 'contrast/agent/telemetry/events/exceptions/obfuscate' module Contrast module Logger # Our decorator for the Ougai logger allowing for the catching, creating and saving Telemetry exceptions module AliasedLogging ALIASED_WARN = 'warn'.cs__freeze ALIASED_ERROR = 'error'.cs__freeze ALIASED_FATAL = 'fatal'.cs__freeze # @param message [String] The message to log. Use default_message if not specified. # @param exception [Exception] The exception or the error # @param data [Object] Any structured data def warn message = nil, exception = nil, data = nil, &block # build Telemetry Exclusion build_exclusion(ALIASED_WARN, message, exception, data) super(message, exception, data, &block) end # @param message [String] The message to log. Use default_message if not specified. # @param exception [Exception] The exception or the error # @param data [Object] Any structured data def error message = nil, exception = nil, data = nil, &block # build Telemetry Exclusion build_exclusion(ALIASED_ERROR, message, exception, data) super(message, exception, data, &block) end # @param message [String] The message to log. Use default_message if not specified. # @param exception [Exception] The exception or the error # @param data [Object] Any structured data def fatal message = nil, exception = nil, data = nil, &block # build Telemetry Exclusion build_exclusion(ALIASED_FATAL, message, exception, data) super(message, exception, data, &block) end private def build_exclusion _type, _message = nil, _exception = nil, _data = nil # TODO: RUBY-1698 nil # start = caller_locations&.find_index { |stack| stack.to_s.include?(type) } # stack_trace = start ? caller_locations(start + 1, 20) : caller_locations(20, 20) # stack_frame_type = Contrast::Agent::Telemetry::TelemetryException::Obfuscate.obfuscate_type( # stack_trace[1].path.delete_prefix(Dir.pwd)) # message_exception_type = Contrast::Agent::Telemetry::TelemetryException::Obfuscate.obfuscate_exception_type( # exception ? exception.cs__class.to_s : stack_frame_type.split('/').last) # stack_frame_function = stack_trace[1].label # key = "#{ stack_frame_type }|#{ stack_frame_function }|#{ message }" # if TELEMETRY_EXCEPTIONS[key] # TELEMETRY_EXCEPTIONS.increment(key) # return # end # # event_message = create_message(stack_frame_function, # stack_frame_type, message_exception_type, # data, exception, # message) # TELEMETRY_EXCEPTIONS[key] = event_message # rescue StandardError => e # debug('Unable to report exception to telemetry', e) end def create_message stack_frame_function, stack_frame_type, message_exception_type, data, exception, message message_for_exception = if exception exception.cs__respond_to?(:message) ? exception.message : exception else message end module_name = message_exception_type ? message_exception_type.split('::')[0] : nil stack_frame = Contrast::Agent::Telemetry::TelemetryException::StackFrame.build(stack_frame_function, stack_frame_type, module_name) message_exception = Contrast::Agent::Telemetry::TelemetryException::MessageException.build( message_exception_type, message_for_exception, module_name, stack_frame) tags = if data data else exception.cs__is_a?(Hash) ? exception : {} end message = Contrast::Agent::Telemetry::TelemetryException::Message.build(tags, [message_exception]) Contrast::Agent::Telemetry::TelemetryException::Event.new(message) end end end end