Class: Fluent::GeoIP

Inherits:
Object
  • Object
show all
Defined in:
lib/fluent/plugin/geoip.rb

Constant Summary collapse

BACKEND_LIBRARIES =
[:geoip, :geoip2_compat, :geoip2_c]
REGEXP_PLACEHOLDER_SINGLE =
/^\$\{(?<geoip_key>-?[^\[]+)\[['"](?<record_key>-?[^'"]+)['"]\]\}$/
REGEXP_PLACEHOLDER_SCAN =
/['"]?(\$\{[^\}]+?\})['"]?/
GEOIP_KEYS =
%w(city latitude longitude country_code3 country_code country_name dma_code area_code region)
GEOIP2_COMPAT_KEYS =
%w(city country_code country_name latitude longitude postal_code region region_name)

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(plugin, conf) ⇒ GeoIP

Returns a new instance of GeoIP.



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/fluent/plugin/geoip.rb', line 25

def initialize(plugin, conf)
  @map = {}
  @geoip_lookup_keys = plugin.geoip_lookup_keys
  if plugin.geoip_lookup_key
    @geoip_lookup_keys = plugin.geoip_lookup_key.split(/\s*,\s*/)
  end
  @skip_adding_null_record = plugin.skip_adding_null_record
  @log = plugin.log

  if conf.keys.any? {|k| k =~ /^enable_key_/ }
    raise Fluent::ConfigError, "geoip: 'enable_key_*' config format is obsoleted. use <record></record> directive instead."
  end

  # <record></record> directive
  conf.elements.select { |element| element.name == 'record' }.each { |element|
    element.each_pair { |k, v|
      element.has_key?(k) # to suppress unread configuration warning
      v = v[1..v.size-2] if quoted_value?(v)
      @map[k] = v
      validate_json = Proc.new {
        begin
          dummy_text = Yajl::Encoder.encode('dummy_text')
          Yajl::Parser.parse(v.gsub(REGEXP_PLACEHOLDER_SCAN, dummy_text))
        rescue Yajl::ParseError => e
          message = "geoip: failed to parse '#{v}' as json."
          log.error message, error: e
          raise Fluent::ConfigError, message
        end
      }
      validate_json.call if json?(v.tr('\'"\\', ''))
    }
  }
  @placeholder_keys = @map.values.join.scan(REGEXP_PLACEHOLDER_SCAN).map{ |placeholder| placeholder[0] }.uniq
  @placeholder_keys.each do |key|
    geoip_key = key.match(REGEXP_PLACEHOLDER_SINGLE)[:geoip_key]
    case plugin.backend_library
    when :geoip
      raise Fluent::ConfigError, "#{plugin.backend_library}: unsupported key #{geoip_key}" unless GEOIP_KEYS.include?(geoip_key)
    when :geoip2_compat
      raise Fluent::ConfigError, "#{plugin.backend_library}: unsupported key #{geoip_key}" unless GEOIP2_COMPAT_KEYS.include?(geoip_key)
    when :geoip2_c
      # Nothing to do.
      # We cannot define supported key(s) before we fetch values from GeoIP2 database
      # because geoip2_c can fetch any fields in GeoIP2 database.
    end
  end

  @geoip = load_database(plugin)
end

Instance Attribute Details

#logObject (readonly)

Returns the value of attribute log.



23
24
25
# File 'lib/fluent/plugin/geoip.rb', line 23

def log
  @log
end

Instance Method Details

#add_geoip_field(record) ⇒ Object



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/fluent/plugin/geoip.rb', line 75

def add_geoip_field(record)
  placeholder = create_placeholder(geolocate(get_address(record)))
  return record if @skip_adding_null_record && placeholder.values.first.nil?
  @map.each do |record_key, value|
    if value.match(REGEXP_PLACEHOLDER_SINGLE)
      rewrited = placeholder[value]
    elsif json?(value)
      rewrited = value.gsub(REGEXP_PLACEHOLDER_SCAN) {|match|
        match = match[1..match.size-2] if quoted_value?(match)
        Yajl::Encoder.encode(placeholder[match])
      }
      rewrited = parse_json(rewrited)
    else
      rewrited = value.gsub(REGEXP_PLACEHOLDER_SCAN, placeholder)
    end
    record[record_key] = rewrited
  end
  return record
end