class Fluent::Plugin::SystemdEntryMutator
A simple stand-alone configurable mutator for systemd journal entries.
Note regarding field mapping: The input `field_map` option is meant to have a structure that is intuative or logical for humans when declaring a field map. {
"<source_field1>" => "<new_field1>", "<source_field2>" => ["<new_field1>", "<new_field2>"]
} Internally the inverse of the human-friendly field_map is computed (and cached) upon object creation and used as a “mapped model” {
"<new_field1>" => ["<source_field1>", "<source_field2>"], "<new_field2>" => ["<source_field2>"]
}
Constants
- Options
Public Class Methods
# File lib/fluent/plugin/systemd/entry_mutator.rb, line 44 def self.default_opts Options.new({}, false, false, false) end
Constructor keyword options (all other kwargs are ignored): field_map - hash describing the desired field mapping in the form:
{"<source_field>" => "<new_field>", ...} where `new_field` is a string or array of strings
field_map_strict - boolean if true will only include new fields
defined in `field_map`
fields_strip_underscores - boolean if true will strip all leading
underscores from non-mapped fields
fields_lowercase - boolean if true lowercase all non-mapped fields
raises `Fluent::ConfigError` for invalid options
# File lib/fluent/plugin/systemd/entry_mutator.rb, line 59 def initialize(**options) @opts = options_from_hash(options) validate_options(@opts) @map = invert_field_map(@opts.field_map) @map_src_fields = @opts.field_map.keys @no_transform = @opts == self.class.default_opts end
Public Instance Methods
Run field formatting (mutations applied to all non-mapped fields) against a single journal entry. Returns the mutated entry hash. entry - hash or `Systemd::Journal:Entry` mapped - Optional hash that represents a previously mapped entry to
which the formatted fields will be added
# File lib/fluent/plugin/systemd/entry_mutator.rb, line 102 def format_fields(entry, mapped = nil) entry.each_with_object(mapped || {}) do |(fld, val), formatted_entry| # don't mess with explicitly mapped fields next if @map_src_fields.include?(fld) fld = format_field_name(fld) # account for mapping (appending) to an existing systemd field formatted_entry[fld] = join_if_needed([val, mapped[fld]]) end end
Run field mapping against a single journal entry. Returns the mutated entry hash. entry - hash or `Systemd::Journal:Entry`
# File lib/fluent/plugin/systemd/entry_mutator.rb, line 89 def map_fields(entry) @map.each_with_object({}) do |(cstm, sysds), mapped| vals = sysds.collect { |fld| entry[fld] }.compact next if vals.empty? # systemd field does not exist in source entry mapped[cstm] = join_if_needed(vals) end end
Expose config state as read-only instance properties of the mutator.
# File lib/fluent/plugin/systemd/entry_mutator.rb, line 68 def method_missing(sym, *args) return @opts[sym] if @opts.members.include?(sym) super end
# File lib/fluent/plugin/systemd/entry_mutator.rb, line 73 def respond_to_missing?(sym, include_private = false) @opts.members.include?(sym) || super end
The main run method that performs all configured mutations, if any, against a single journal entry. Returns the mutated entry hash. entry - hash or `Systemd::Journal:Entry`
# File lib/fluent/plugin/systemd/entry_mutator.rb, line 80 def run(entry) return entry.to_h if @no_transform return map_fields(entry) if @opts.field_map_strict format_fields(entry, map_fields(entry)) end
# File lib/fluent/plugin/systemd/entry_mutator.rb, line 112 def warnings return [] unless field_map_strict && field_map.empty? '`field_map_strict` set to true with empty `field_map`, expect no fields' end
Private Instance Methods
# File lib/fluent/plugin/systemd/entry_mutator.rb, line 125 def format_field_name(name) name = name.gsub(/\A_+/, '') if @opts.fields_strip_underscores name = name.downcase if @opts.fields_lowercase name end
Compute the inverse of a human friendly field map `field_map` which is what the mutator uses for the actual mapping. The resulting structure for the inverse field map hash is: {“<new_field_name>” => [“<source_field_name>”, …], …}
# File lib/fluent/plugin/systemd/entry_mutator.rb, line 164 def invert_field_map(field_map) invs = {} field_map.values.flatten.uniq.each do |cstm| sysds = field_map.select { |_, v| (v == cstm || v.include?(cstm)) } invs[cstm] = sysds.keys end invs end
# File lib/fluent/plugin/systemd/entry_mutator.rb, line 119 def join_if_needed(values) values.compact! return values.first if values.length == 1 values.join(' ') end
Returns a `SystemdEntryMutator::Options` struct derived from the elements in the supplied hash merged with the option defaults
# File lib/fluent/plugin/systemd/entry_mutator.rb, line 133 def options_from_hash(opts) merged = self.class.default_opts merged.each_pair do |k, _| merged[k] = opts[k] if opts.key?(k) end merged end
# File lib/fluent/plugin/systemd/entry_mutator.rb, line 149 def validate_all_strings(arr, message, allow_nesting = false) valid = arr.all? do |value| value.is_a?(String) || allow_nesting && value.is_a?(Array) && value.all? { |key| key.is_a?(String) } end raise Fluent::ConfigError, message unless valid end
# File lib/fluent/plugin/systemd/entry_mutator.rb, line 156 def validate_boolean(value, name) raise Fluent::ConfigError, "`#{name}` must be boolean" unless [true, false].include?(value) end
# File lib/fluent/plugin/systemd/entry_mutator.rb, line 141 def validate_options(opts) validate_all_strings opts[:field_map].keys, '`field_map` keys must be strings' validate_all_strings opts[:field_map].values, '`field_map` values must be strings or an array of strings', true %i[field_map_strict fields_strip_underscores fields_lowercase].each do |opt| validate_boolean opts[opt], opt end end