Module: NewRelic::Agent::AttributePreFiltering

Defined in:
lib/new_relic/agent/attribute_pre_filtering.rb

Constant Summary collapse

PRE_FILTER_KEYS =
%i[include exclude].freeze
DISCARDED =
:nr_discarded

Class Method Summary collapse

Class Method Details

.discarded?(object) ⇒ Boolean

‘nil`, empty enumerable objects, and `false` are all valid in their own right as application data, so pre-filtering uses a special value to indicate that filtered out data has been discarded

Returns:

  • (Boolean)


104
105
106
# File 'lib/new_relic/agent/attribute_pre_filtering.rb', line 104

def discarded?(object)
  object == DISCARDED
end

.formulate_regexp_union(option) ⇒ Object



13
14
15
16
17
18
19
20
# File 'lib/new_relic/agent/attribute_pre_filtering.rb', line 13

def formulate_regexp_union(option)
  return if NewRelic::Agent.config[option].empty?

  Regexp.union(NewRelic::Agent.config[option].map { |p| string_to_regexp(p) }.uniq.compact).freeze
rescue StandardError => e
  NewRelic::Agent.logger.warn("Failed to formulate a Regexp union from the '#{option}' configuration option " +
                              "- #{e.class}: #{e.message}")
end

.pre_filter(values = [], options = {}) ⇒ Object

attribute filtering suppresses data that has already been flattened and coerced (serialized as text) via #flatten_and_coerce, and is restricted to basic text matching with a single optional wildcard. pre filtering operates on raw Ruby objects beforehand and uses full Ruby regex syntax



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/new_relic/agent/attribute_pre_filtering.rb', line 33

def pre_filter(values = [], options = {})
  return values unless !options.empty? && PRE_FILTER_KEYS.any? { |k| options.key?(k) }

  # if there's a prefix in play for (non-pre) attribute filtration and
  # attribute filtration won't allow that prefix, then don't even bother
  # with pre filtration that could only result in values that would be
  # blocked
  if options.key?(:attribute_namespace) &&
      !NewRelic::Agent.instance.attribute_filter.might_allow_prefix?(options[:attribute_namespace])
    return values
  end

  values.each_with_object([]) do |element, filtered|
    object = pre_filter_object(element, options)
    filtered << object unless discarded?(object)
  end
end

.pre_filter_array(array, options) ⇒ Object



83
84
85
86
87
88
89
90
91
92
# File 'lib/new_relic/agent/attribute_pre_filtering.rb', line 83

def pre_filter_array(array, options)
  filtered_array = array.each_with_object([]) do |element, filtered|
    filtered_element = pre_filter_object(element, options)
    next if discarded?(filtered_element)

    filtered.push(filtered_element)
  end

  filtered_array.empty? && !array.empty? ? DISCARDED : filtered_array
end

.pre_filter_hash(hash, options) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/new_relic/agent/attribute_pre_filtering.rb', line 61

def pre_filter_hash(hash, options)
  filtered_hash = hash.each_with_object({}) do |(key, value), filtered|
    filtered_key = pre_filter_object(key, options)
    next if discarded?(filtered_key)

    # If the key is permitted, skip include filtration for the value
    # but still apply exclude filtration
    if options.key?(:exclude)
      exclude_only = options.dup
      exclude_only.delete(:include)
      filtered_value = pre_filter_object(value, exclude_only)
      next if discarded?(filtered_value)
    else
      filtered_value = value
    end

    filtered[filtered_key] = filtered_value
  end

  filtered_hash.empty? && !hash.empty? ? DISCARDED : filtered_hash
end

.pre_filter_object(object, options) ⇒ Object



51
52
53
54
55
56
57
58
59
# File 'lib/new_relic/agent/attribute_pre_filtering.rb', line 51

def pre_filter_object(object, options)
  if object.is_a?(Hash)
    pre_filter_hash(object, options)
  elsif object.is_a?(Array)
    pre_filter_array(object, options)
  else
    pre_filter_scalar(object, options)
  end
end

.pre_filter_scalar(scalar, options) ⇒ Object



94
95
96
97
98
99
# File 'lib/new_relic/agent/attribute_pre_filtering.rb', line 94

def pre_filter_scalar(scalar, options)
  return DISCARDED if options.key?(:include) && !scalar.to_s.match?(options[:include])
  return DISCARDED if options.key?(:exclude) && scalar.to_s.match?(options[:exclude])

  scalar
end

.string_to_regexp(str) ⇒ Object



22
23
24
25
26
# File 'lib/new_relic/agent/attribute_pre_filtering.rb', line 22

def string_to_regexp(str)
  Regexp.new(str)
rescue StandardError => e
  NewRelic::Agent.logger.warn("Failed to initialize Regexp from string '#{str}' - #{e.class}: #{e.message}")
end