# typed: ignore # Copyright (c) 2015 Sqreen. All Rights Reserved. # Please refer to our terms for more information: https://www.sqreen.com/terms.html # TODO: Sqreen::Attack => sqreen/events # TODO: Sqreen::RemoteException => sqreen/events # TODO: Sqreen::RequestRecord => sqreen/events # TODO: Sqreen.time require 'sqreen/aggregated_metric' require 'sqreen/events/attack' require 'sqreen/events/remote_exception' require 'sqreen/mono_time' require 'sqreen/deliveries/simple' require 'sqreen/kit/signals/signal' require 'sqreen/kit/signals/trace' module Sqreen module Deliveries # Simple delivery method that batch event already seen in a batch class Batch < Simple attr_accessor :max_batch, :max_staleness attr_accessor :current_batch, :first_seen def initialize(session, max_batch, max_staleness, randomize_staleness = true) super(session) self.max_batch = max_batch self.max_staleness = max_staleness @original_max_staleness = max_staleness self.current_batch = [] @first_seen = {} @randomize_staleness = randomize_staleness end def post_event(event) current_batch.push(event) post_batch if post_batch_needed?(event) end def drain post_batch unless current_batch.empty? end def tick post_batch if !current_batch.empty? && stale? end protected def stale? min = @first_seen.values.min return false if min.nil? (min + max_staleness) < Sqreen.time end def post_batch_needed?(event) now = Sqreen.time # do not use any? {} due to side effects inside block event_keys(event).uniq.map do |key| was = @first_seen[key] @first_seen[key] ||= now was.nil? || current_batch.size > max_batch || now > (was + max_staleness) end.any? end def post_batch session.post_batch(current_batch) current_batch.clear now = Sqreen.time @first_seen.each_key do |key| @first_seen[key] = now end return unless @randomize_staleness self.max_staleness = @original_max_staleness # Adds up to 10% of lateness self.max_staleness += rand(@original_max_staleness / 10) end def event_keys(event) return [event_key(event)] unless event.is_a?(Sqreen::RequestRecord) res = [] res += event.observed.fetch(:attacks, []).map { |e| "att-#{e[:rule_name]}" } res += event.observed.fetch(:sqreen_exceptions, []).map { |e| "rex-#{e[:exception].class}" } res += event.observed.fetch(:sdk, []).select { |e| e[0] == :track }.map { |e| "sdk-track".freeze } res += event.observed.fetch(:signals, []).map { "signal".freeze } return res end def event_key(event) case event when Sqreen::Attack "att-#{event.rule_name}" when Sqreen::RemoteException "rex-#{event.klass}" when Sqreen::AggregatedMetric "agg-metric" when Sqreen::Kit::Signals::Signal "signal" when Sqreen::Kit::Signals::Trace "signal" end end end end end