Class: PgCanary::Detector

Inherits:
Object
  • Object
show all
Defined in:
lib/pg_canary/detector.rb

Overview

Parses an event's SQL, runs every enabled rule against it, and filters ignored tables. Each returned Detection carries the query's fingerprint, so a consumer that sees the same query and rule repeatedly (e.g. an N+1 loop within one request) can collapse them — see Middleware.

Instance Method Summary collapse

Constructor Details

#initialize(config) ⇒ Detector

Swallows the configuration whole at construction: pg_canary treats it as fixed after boot (set in an initializer).



15
16
17
18
19
20
21
22
23
# File 'lib/pg_canary/detector.rb', line 15

def initialize(config)
  @config = config
  @rule_classes = Rules::Base.all.select { |klass| klass.enabled?(config) }
  @backtrace_cleaner = ActiveSupport::BacktraceCleaner.new.tap do |cleaner|
    root = config.app_root
    cleaner.add_silencer { |line| line.include?("lib/pg_canary") }
    cleaner.add_filter { |line| line.delete_prefix("#{root}/") } if root
  end
end

Instance Method Details

#call(payload) ⇒ Object

=> [Detection] the detections that should be notified.



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/pg_canary/detector.rb', line 26

def call(payload)
  state = build_state(payload)
  return [] unless state

  location = nil
  fingerprint = nil
  @rule_classes.flat_map do |klass|
    detections = check_rule(klass, state)
    next [] if detections.empty?

    location ||= source_location
    fingerprint ||= PgQuery.fingerprint(state[:sql])
    detections.each do |d|
      d.location = location
      d.fingerprint = fingerprint
    end
  end
end