Class: LogStash::Filters::GeoIP

Inherits:
Base show all
Defined in:
lib/logstash/filters/geoip.rb

Overview

Add GeoIP fields from Maxmind database

GeoIP filter, adds information about the geographical location of IP addresses.

Starting at version 1.3.0 of logstash, a [geoip] field is created if the GeoIP lookup returns a latitude and longitude. The field is stored in [GeoJSON](geojson.org/geojson-spec.html) format. Additionally, the default Elasticsearch template provided with the [elasticsearch output](../outputs/elasticsearch.html) maps the [geoip] field to a [geo_point](www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping-geo-point-type.html).

As this field is a geo_point and it is still valid GeoJSON, you get the awesomeness of Elasticsearch’s geospatial query, facet and filter functions and the flexibility of having GeoJSON for all other applications (like Kibana’s [bettermap panel](github.com/elasticsearch/kibana/tree/master/src/app/panels/bettermap)).

Logstash releases ship with the GeoLiteCity database made available from Maxmind with a CCA-ShareAlike 3.0 license. For more details on GeoLite, see <www.maxmind.com/en/geolite>.

Constant Summary

Constants inherited from Base

Base::RESERVED

Constants included from Config::Mixin

Config::Mixin::CONFIGSORT

Instance Attribute Summary

Attributes included from Config::Mixin

#config, #original_params

Attributes inherited from Plugin

#logger, #params

Instance Method Summary collapse

Methods inherited from Base

#execute, #initialize, #threadsafe?

Methods included from Config::Mixin

#config_init, included

Methods inherited from Plugin

#eql?, #finished, #finished?, #hash, #initialize, #inspect, lookup, #reload, #running?, #shutdown, #teardown, #terminating?, #to_s

Constructor Details

This class inherits a constructor from LogStash::Filters::Base

Instance Method Details

#filter(event) ⇒ Object



107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/logstash/filters/geoip.rb', line 107

def filter(event)
  return unless filter?(event)
  geo_data = nil

  begin
    ip = event[@source]
    ip = ip.first if ip.is_a? Array
    geo_data = @geoip.send(@geoip_type, ip)
  rescue SocketError => e
    @logger.error("IP Field contained invalid IP address or hostname", :field => @field, :event => event)
  rescue Exception => e
    @logger.error("Unknown error while looking up GeoIP data", :exception => e, :field => @field, :event => event)
  end

  return if geo_data.nil?

  geo_data_hash = geo_data.to_hash
  geo_data_hash.delete(:request)
  event[@target] = {} if event[@target].nil?
  geo_data_hash.each do |key, value|
    next if value.nil? || (value.is_a?(String) && value.empty?)
    if @fields.nil? || @fields.empty?
      # no fields requested, so add all geoip hash items to
      # the event's fields.
      # convert key to string (normally a Symbol)
      event[@target][key.to_s] = value
    elsif @fields.include?(key.to_s)
      # Check if the key is in our fields array
      # convert key to string (normally a Symbol)
      event[@target][key.to_s] = value
    end
  end # geo_data_hash.each
  if event[@target].key?('latitude') && event[@target].key?('longitude')
    # If we have latitude and longitude values, add the location field as GeoJSON array
    event[@target]['location'] = [ event[@target]["longitude"].to_f, event[@target]["latitude"].to_f ]
  end
  filter_matched(event)
end

#registerObject



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/logstash/filters/geoip.rb', line 64

def register
  require "geoip"
  if @database.nil?
    if __FILE__ =~ /^(jar:)?file:\/.+!.+/
      begin
        # Running from a jar, assume GeoLiteCity.dat is at the root.
        jar_path = [__FILE__.split("!").first, "/GeoLiteCity.dat"].join("!")
        tmp_file = Tempfile.new('logstash-geoip')
        tmp_file.write(File.read(jar_path))
        tmp_file.close # this file is reaped when ruby exits
        @database = tmp_file.path
      rescue => ex
        raise "Failed to cache, due to: #{ex}\n#{ex.backtrace}"
      end
    else
      if File.exists?("GeoLiteCity.dat")
        @database = "GeoLiteCity.dat"
      elsif File.exists?("vendor/geoip/GeoLiteCity.dat")
        @database = "vendor/geoip/GeoLiteCity.dat"
      else
        raise "You must specify 'database => ...' in your geoip filter"
      end
    end
  end
  @logger.info("Using geoip database", :path => @database)
  @geoip = ::GeoIP.new(@database)

  @geoip_type = case @geoip.database_type
  when GeoIP::GEOIP_CITY_EDITION_REV0, GeoIP::GEOIP_CITY_EDITION_REV1
    :city
  when GeoIP::GEOIP_COUNTRY_EDITION
    :country
  when GeoIP::GEOIP_ASNUM_EDITION
    :asn
  when GeoIP::GEOIP_ISP_EDITION, GeoIP::GEOIP_ORG_EDITION
    :isp
  else
    raise RuntimeException.new "This GeoIP database is not currently supported"
  end

end