Class: Appsignal::Aggregator::Middleware::ActiveRecordSanitizer

Inherits:
Object
  • Object
show all
Defined in:
lib/appsignal/aggregator/middleware/active_record_sanitizer.rb

Constant Summary collapse

TARGET_EVENT_NAME =
'sql.active_record'.freeze
SINGLE_QUOTE =
/\\'/.freeze
DOUBLE_QUOTE =
/\\"/.freeze
QUOTED_DATA =
/(?:"[^"]+"|'[^']+')/.freeze
SINGLE_QUOTED_DATA =
/(?:'[^']+')/.freeze
IN_ARRAY =
/(IN \()[^\)]+(\))/.freeze
NUMERIC_DATA =
/\b\d+\b/.freeze
SANITIZED_VALUE =
'\1?\2'.freeze

Instance Method Summary collapse

Instance Method Details

#adapter_uses_double_quoted_table_names?Boolean

Returns:

  • (Boolean)


52
53
54
55
# File 'lib/appsignal/aggregator/middleware/active_record_sanitizer.rb', line 52

def adapter_uses_double_quoted_table_names?
  adapter = connection_config[:adapter]
  adapter =~ /postgres/ || adapter =~ /sqlite/
end

#adapter_uses_prepared_statements?Boolean

Returns:

  • (Boolean)


57
58
59
60
61
# File 'lib/appsignal/aggregator/middleware/active_record_sanitizer.rb', line 57

def adapter_uses_prepared_statements?
  return false unless adapter_uses_double_quoted_table_names?
  return true if connection_config[:prepared_statements].nil?
  connection_config[:prepared_statements]
end

#call(event) ⇒ Object



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/appsignal/aggregator/middleware/active_record_sanitizer.rb', line 16

def call(event)
  if event.name == TARGET_EVENT_NAME
    unless schema_query?(event) || adapter_uses_prepared_statements?
      query_string = event.payload[:sql].dup
      if query_string
        if adapter_uses_double_quoted_table_names?
          query_string.gsub!(SINGLE_QUOTE, SANITIZED_VALUE)
          query_string.gsub!(SINGLE_QUOTED_DATA, SANITIZED_VALUE)
        else
          query_string.gsub!(SINGLE_QUOTE, SANITIZED_VALUE)
          query_string.gsub!(DOUBLE_QUOTE, SANITIZED_VALUE)
          query_string.gsub!(QUOTED_DATA, SANITIZED_VALUE)
        end
        query_string.gsub!(IN_ARRAY, SANITIZED_VALUE)
        query_string.gsub!(NUMERIC_DATA, SANITIZED_VALUE)
        event.payload[:sql] = query_string
      end
    end
    event.payload.delete(:connection_id)
    event.payload.delete(:binds)
  end
  yield
end

#connection_configObject



44
45
46
47
48
49
50
# File 'lib/appsignal/aggregator/middleware/active_record_sanitizer.rb', line 44

def connection_config
  @connection_config ||= if ActiveRecord::Base.respond_to?(:connection_config)
    ActiveRecord::Base.connection_config
  else
    ActiveRecord::Base.connection_pool.spec.config
  end
end

#schema_query?(event) ⇒ Boolean

Returns:

  • (Boolean)


40
41
42
# File 'lib/appsignal/aggregator/middleware/active_record_sanitizer.rb', line 40

def schema_query?(event)
  event.payload[:name] == 'SCHEMA'
end