Class: NewRelic::Agent::AttributeFilter
- Inherits:
-
Object
- Object
- NewRelic::Agent::AttributeFilter
- Defined in:
- lib/new_relic/agent/attribute_filter.rb
Constant Summary collapse
- DST_NONE =
0x0
- DST_TRANSACTION_EVENTS =
1 << 0
- DST_TRANSACTION_TRACER =
1 << 1
- DST_ERROR_COLLECTOR =
1 << 2
- DST_BROWSER_MONITORING =
1 << 3
- DST_SPAN_EVENTS =
1 << 4
- DST_TRANSACTION_SEGMENTS =
1 << 5
- DST_ALL =
0x3f
Instance Attribute Summary collapse
-
#rules ⇒ Object
readonly
Returns the value of attribute rules.
Instance Method Summary collapse
- #allows?(allowed_destinations, requested_destination) ⇒ Boolean
- #allows_key?(key, destination) ⇒ Boolean
- #apply(attribute_name, default_destinations) ⇒ Object
- #build_rule(attribute_names, destinations, is_include) ⇒ Object
- #build_uri_rule(excluded_attributes) ⇒ Object
-
#cache_prefix_denylist ⇒ Object
For attribute prefixes where we know the default destinations will always be DST_NONE, we can statically determine that any attribute starting with the prefix will not be allowed unless there’s an include rule that might match attributes starting with it.
- #enabled_destinations_for_attributes(config) ⇒ Object
- #high_security? ⇒ Boolean
- #include_destinations_for_capture_params(capturing) ⇒ Object
-
#initialize(config) ⇒ AttributeFilter
constructor
A new instance of AttributeFilter.
-
#might_allow_prefix?(prefix) ⇒ Boolean
Note that the given prefix must be a Symbol.
- #might_allow_prefix_uncached?(prefix) ⇒ Boolean
- #prep_attributes_exclude_rules(config) ⇒ Object
- #prep_attributes_include_rules(config) ⇒ Object
- #prep_capture_params_rules(config) ⇒ Object
- #prep_datastore_rules(config) ⇒ Object
- #prep_enabled_destinations(config) ⇒ Object
- #prep_rules(config) ⇒ Object
-
#setup_key_cache ⇒ Object
Note the key_cache is a global cache, accessible by multiple threads, but is intentionally left unsynchronized for liveness.
Constructor Details
#initialize(config) ⇒ AttributeFilter
Returns a new instance of AttributeFilter.
78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/new_relic/agent/attribute_filter.rb', line 78 def initialize(config) prep_enabled_destinations(config) prep_rules(config) # We're ok to cache high security for fast lookup because the attribute # filter is re-generated on any significant config change. @high_security = config[:high_security] setup_key_cache cache_prefix_denylist end |
Instance Attribute Details
#rules ⇒ Object (readonly)
Returns the value of attribute rules.
76 77 78 |
# File 'lib/new_relic/agent/attribute_filter.rb', line 76 def rules @rules end |
Instance Method Details
#allows?(allowed_destinations, requested_destination) ⇒ Boolean
211 212 213 |
# File 'lib/new_relic/agent/attribute_filter.rb', line 211 def allows?(allowed_destinations, requested_destination) allowed_destinations & requested_destination == requested_destination end |
#allows_key?(key, destination) ⇒ Boolean
215 216 217 218 219 220 221 222 223 224 225 226 |
# File 'lib/new_relic/agent/attribute_filter.rb', line 215 def allows_key?(key, destination) return false unless destination & @enabled_destinations == destination value = @key_cache[destination][key] if value.nil? allowed_destinations = apply(key, destination) @key_cache[destination][key] = allows?(allowed_destinations, destination) else value end end |
#apply(attribute_name, default_destinations) ⇒ Object
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 |
# File 'lib/new_relic/agent/attribute_filter.rb', line 192 def apply(attribute_name, default_destinations) return DST_NONE if @enabled_destinations == DST_NONE destinations = default_destinations attribute_name = attribute_name.to_s @rules.each do |rule| if rule.match?(attribute_name) if rule.is_include destinations |= rule.destinations else destinations &= rule.destinations end end end destinations & @enabled_destinations end |
#build_rule(attribute_names, destinations, is_include) ⇒ Object
177 178 179 180 181 182 |
# File 'lib/new_relic/agent/attribute_filter.rb', line 177 def build_rule(attribute_names, destinations, is_include) attribute_names.each do |attribute_name| rule = AttributeFilterRule.new(attribute_name, destinations, is_include) @rules << rule unless rule.empty? end end |
#build_uri_rule(excluded_attributes) ⇒ Object
184 185 186 187 188 189 190 |
# File 'lib/new_relic/agent/attribute_filter.rb', line 184 def build_uri_rule(excluded_attributes) uri_aliases = %w[uri url request_uri request.uri http.url] if (excluded_attributes & uri_aliases).size > 0 build_rule(uri_aliases - excluded_attributes, DST_ALL, false) end end |
#cache_prefix_denylist ⇒ Object
For attribute prefixes where we know the default destinations will always be DST_NONE, we can statically determine that any attribute starting with the prefix will not be allowed unless there’s an include rule that might match attributes starting with it.
This allows us to skip significant preprocessing work (hash/array flattening and type coercion) for HTTP request parameters and job arguments for Sidekiq and Resque in the common case, since none of these attributes are captured by default.
242 243 244 245 246 247 |
# File 'lib/new_relic/agent/attribute_filter.rb', line 242 def cache_prefix_denylist @prefix_denylist = {} @prefix_denylist[:'request.parameters'] = true unless might_allow_prefix_uncached?(:'request.parameters') @prefix_denylist[:'job.sidekiq.args'] = true unless might_allow_prefix_uncached?(:'job.sidekiq.args') @prefix_denylist[:'job.resque.args'] = true unless might_allow_prefix_uncached?(:'job.resque.args') end |
#enabled_destinations_for_attributes(config) ⇒ Object
94 95 96 97 98 99 100 101 102 103 |
# File 'lib/new_relic/agent/attribute_filter.rb', line 94 def enabled_destinations_for_attributes(config) destinations = DST_NONE destinations |= DST_TRANSACTION_TRACER if config[:'transaction_tracer.attributes.enabled'] destinations |= DST_TRANSACTION_EVENTS if config[:'transaction_events.attributes.enabled'] destinations |= DST_ERROR_COLLECTOR if config[:'error_collector.attributes.enabled'] destinations |= DST_BROWSER_MONITORING if config[:'browser_monitoring.attributes.enabled'] destinations |= DST_SPAN_EVENTS if config[:'span_events.attributes.enabled'] destinations |= DST_TRANSACTION_SEGMENTS if config[:'transaction_segments.attributes.enabled'] destinations end |
#high_security? ⇒ Boolean
228 229 230 |
# File 'lib/new_relic/agent/attribute_filter.rb', line 228 def high_security? @high_security end |
#include_destinations_for_capture_params(capturing) ⇒ Object
169 170 171 172 173 174 175 |
# File 'lib/new_relic/agent/attribute_filter.rb', line 169 def include_destinations_for_capture_params(capturing) if capturing DST_TRANSACTION_TRACER | DST_ERROR_COLLECTOR else DST_NONE end end |
#might_allow_prefix?(prefix) ⇒ Boolean
Note that the given prefix must be a Symbol
250 251 252 |
# File 'lib/new_relic/agent/attribute_filter.rb', line 250 def might_allow_prefix?(prefix) !@prefix_denylist.include?(prefix) end |
#might_allow_prefix_uncached?(prefix) ⇒ Boolean
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 |
# File 'lib/new_relic/agent/attribute_filter.rb', line 254 def might_allow_prefix_uncached?(prefix) prefix = prefix.to_s @rules.any? do |rule| if rule.is_include if rule.wildcard if rule.attribute_name.size > prefix.size rule.attribute_name.start_with?(prefix) else prefix.start_with?(rule.attribute_name) end else rule.attribute_name.start_with?(prefix) end end end end |
#prep_attributes_exclude_rules(config) ⇒ Object
115 116 117 118 119 120 121 122 123 |
# File 'lib/new_relic/agent/attribute_filter.rb', line 115 def prep_attributes_exclude_rules(config) build_rule(config[:'attributes.exclude'], DST_ALL, false) build_rule(config[:'transaction_tracer.attributes.exclude'], DST_TRANSACTION_TRACER, false) build_rule(config[:'transaction_events.attributes.exclude'], DST_TRANSACTION_EVENTS, false) build_rule(config[:'error_collector.attributes.exclude'], DST_ERROR_COLLECTOR, false) build_rule(config[:'browser_monitoring.attributes.exclude'], DST_BROWSER_MONITORING, false) build_rule(config[:'span_events.attributes.exclude'], DST_SPAN_EVENTS, false) build_rule(config[:'transaction_segments.attributes.exclude'], DST_TRANSACTION_SEGMENTS, false) end |
#prep_attributes_include_rules(config) ⇒ Object
134 135 136 137 138 139 140 141 142 |
# File 'lib/new_relic/agent/attribute_filter.rb', line 134 def prep_attributes_include_rules(config) build_rule(config[:'attributes.include'], DST_ALL, true) build_rule(config[:'transaction_tracer.attributes.include'], DST_TRANSACTION_TRACER, true) build_rule(config[:'transaction_events.attributes.include'], DST_TRANSACTION_EVENTS, true) build_rule(config[:'error_collector.attributes.include'], DST_ERROR_COLLECTOR, true) build_rule(config[:'browser_monitoring.attributes.include'], DST_BROWSER_MONITORING, true) build_rule(config[:'span_events.attributes.include'], DST_SPAN_EVENTS, true) build_rule(config[:'transaction_segments.attributes.include'], DST_TRANSACTION_SEGMENTS, true) end |
#prep_capture_params_rules(config) ⇒ Object
125 126 127 |
# File 'lib/new_relic/agent/attribute_filter.rb', line 125 def prep_capture_params_rules(config) build_rule(['request.parameters.*'], include_destinations_for_capture_params(config[:capture_params]), true) end |
#prep_datastore_rules(config) ⇒ Object
129 130 131 132 |
# File 'lib/new_relic/agent/attribute_filter.rb', line 129 def prep_datastore_rules(config) build_rule(%w[host port_path_or_id], DST_TRANSACTION_SEGMENTS, config[:'datastore_tracer.instance_reporting.enabled']) build_rule(['database_name'], DST_TRANSACTION_SEGMENTS, config[:'datastore_tracer.database_name_reporting.enabled']) end |
#prep_enabled_destinations(config) ⇒ Object
90 91 92 |
# File 'lib/new_relic/agent/attribute_filter.rb', line 90 def prep_enabled_destinations(config) @enabled_destinations = config[:'attributes.enabled'] ? enabled_destinations_for_attributes(config) : DST_NONE end |
#prep_rules(config) ⇒ Object
105 106 107 108 109 110 111 112 113 |
# File 'lib/new_relic/agent/attribute_filter.rb', line 105 def prep_rules(config) @rules = [] prep_attributes_exclude_rules(config) prep_capture_params_rules(config) prep_datastore_rules(config) prep_attributes_include_rules(config) build_uri_rule(config[:'attributes.exclude']) @rules.sort! end |
#setup_key_cache ⇒ Object
Note the key_cache is a global cache, accessible by multiple threads, but is intentionally left unsynchronized for liveness. Writes will always involve writing the same boolean value for each key, so there is no worry of one value clobbering another. For reads, if a value hasn’t been written to the cache yet, the worst that will happen is that it will run through the filter rules again. Both reads and writes will become eventually consistent.
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
# File 'lib/new_relic/agent/attribute_filter.rb', line 152 def setup_key_cache destinations = [ DST_TRANSACTION_EVENTS, DST_TRANSACTION_TRACER, DST_ERROR_COLLECTOR, DST_BROWSER_MONITORING, DST_SPAN_EVENTS, DST_TRANSACTION_SEGMENTS, DST_ALL ] @key_cache = destinations.inject({}) do |memo, destination| memo[destination] = {} memo end end |