class NewRelic::Agent::AttributeFilter
Constants
- DST_ALL
- DST_BROWSER_MONITORING
- DST_ERROR_COLLECTOR
- DST_NONE
- DST_SPAN_EVENTS
- DST_TRANSACTION_EVENTS
- DST_TRANSACTION_SEGMENTS
- DST_TRANSACTION_TRACER
Attributes
Public Class Methods
Source
# 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
Public Instance Methods
Source
# File lib/new_relic/agent/attribute_filter.rb, line 211 def allows?(allowed_destinations, requested_destination) allowed_destinations & requested_destination == requested_destination end
Source
# 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
Source
# 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
Source
# 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
Source
# 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
Source
# 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
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.
Source
# 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
Source
# File lib/new_relic/agent/attribute_filter.rb, line 228 def high_security? @high_security end
Source
# 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
Source
# File lib/new_relic/agent/attribute_filter.rb, line 250 def might_allow_prefix?(prefix) !@prefix_denylist.include?(prefix) end
Note that the given prefix must be a Symbol
Source
# 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
Source
# 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
Source
# 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
Source
# 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
Source
# 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
Source
# 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
Source
# 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
Source
# 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
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.