diff options
Diffstat (limited to 'lib/gitlab/error_tracking/processor/grpc_error_processor.rb')
-rw-r--r-- | lib/gitlab/error_tracking/processor/grpc_error_processor.rb | 166 |
1 files changed, 116 insertions, 50 deletions
diff --git a/lib/gitlab/error_tracking/processor/grpc_error_processor.rb b/lib/gitlab/error_tracking/processor/grpc_error_processor.rb index 871e9c4b7c8..419098dbd09 100644 --- a/lib/gitlab/error_tracking/processor/grpc_error_processor.rb +++ b/lib/gitlab/error_tracking/processor/grpc_error_processor.rb @@ -6,60 +6,126 @@ module Gitlab class GrpcErrorProcessor < ::Raven::Processor DEBUG_ERROR_STRING_REGEX = RE2('(.*) debug_error_string:(.*)') - def process(value) - process_first_exception_value(value) - process_custom_fingerprint(value) + def process(payload) + return payload if ::Feature.enabled?(:sentry_processors_before_send, default_enabled: :yaml) - value - end - - # Sentry can report multiple exceptions in an event. Sanitize - # only the first one since that's what is used for grouping. - def process_first_exception_value(value) - exceptions = value.dig(:exception, :values) - - return unless exceptions.is_a?(Array) - - entry = exceptions.first - - return unless entry.is_a?(Hash) - - exception_type = entry[:type] - raw_message = entry[:value] - - return unless exception_type&.start_with?('GRPC::') - return unless raw_message.present? - - message, debug_str = split_debug_error_string(raw_message) - - entry[:value] = message if message - extra = value[:extra] || {} - extra[:grpc_debug_error_string] = debug_str if debug_str - end - - def process_custom_fingerprint(value) - fingerprint = value[:fingerprint] - - return value unless custom_grpc_fingerprint?(fingerprint) + self.class.process_first_exception_value(payload) + self.class.process_custom_fingerprint(payload) - message, _ = split_debug_error_string(fingerprint[1]) - fingerprint[1] = message if message + payload end - private - - def custom_grpc_fingerprint?(fingerprint) - fingerprint.is_a?(Array) && fingerprint.length == 2 && fingerprint[0].start_with?('GRPC::') - end - - def split_debug_error_string(message) - return unless message - - match = DEBUG_ERROR_STRING_REGEX.match(message) - - return unless match - - [match[1], match[2]] + class << self + def call(event) + return event unless ::Feature.enabled?(:sentry_processors_before_send, default_enabled: :yaml) + + process_first_exception_value(event) + process_custom_fingerprint(event) + + event + end + + # Sentry can report multiple exceptions in an event. Sanitize + # only the first one since that's what is used for grouping. + def process_first_exception_value(event_or_payload) + exceptions = exceptions(event_or_payload) + + return unless exceptions.is_a?(Array) + + exception = exceptions.first + + return unless valid_exception?(exception) + + exception_type, raw_message = type_and_value(exception) + + return unless exception_type&.start_with?('GRPC::') + return unless raw_message.present? + + message, debug_str = split_debug_error_string(raw_message) + + set_new_values!(event_or_payload, exception, message, debug_str) + end + + def process_custom_fingerprint(event) + fingerprint = fingerprint(event) + + return event unless custom_grpc_fingerprint?(fingerprint) + + message, _ = split_debug_error_string(fingerprint[1]) + fingerprint[1] = message if message + end + + private + + def custom_grpc_fingerprint?(fingerprint) + fingerprint.is_a?(Array) && fingerprint.length == 2 && fingerprint[0].start_with?('GRPC::') + end + + def split_debug_error_string(message) + return unless message + + match = DEBUG_ERROR_STRING_REGEX.match(message) + + return unless match + + [match[1], match[2]] + end + + # The below methods can be removed once we remove the + # sentry_processors_before_send feature flag, and we can + # assume we always have an Event object + def exceptions(event_or_payload) + case event_or_payload + when Raven::Event + # Better in new version, will be event_or_payload.exception.values + event_or_payload.instance_variable_get(:@interfaces)[:exception]&.values + when Hash + event_or_payload.dig(:exception, :values) + end + end + + def valid_exception?(exception) + case exception + when Raven::SingleExceptionInterface + exception&.value + when Hash + true + else + false + end + end + + def type_and_value(exception) + case exception + when Raven::SingleExceptionInterface + [exception.type, exception.value] + when Hash + exception.values_at(:type, :value) + end + end + + def set_new_values!(event_or_payload, exception, message, debug_str) + case event_or_payload + when Raven::Event + # Worse in new version, no setter! Have to poke at the + # instance variable + exception.value = message if message + event_or_payload.extra[:grpc_debug_error_string] = debug_str if debug_str + when Hash + exception[:value] = message if message + extra = event_or_payload[:extra] || {} + extra[:grpc_debug_error_string] = debug_str if debug_str + end + end + + def fingerprint(event_or_payload) + case event_or_payload + when Raven::Event + event_or_payload.fingerprint + when Hash + event_or_payload[:fingerprint] + end + end end end end |