Class: LogStash::Filters::GeoIP

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

Overview

The GeoIP filter adds information about the geographical location of IP addresses, based on data from the MaxMind GeoLite2 database.

A ‘[geoip]` field is created if the GeoIP lookup returns a latitude and longitude. The field is stored in geojson.org/geojson-spec.html[GeoJSON] format. Additionally, the default Elasticsearch template provided with the <<plugins-outputs-elasticsearch,`elasticsearch` output>> maps the `[geoip]` field to an www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping-geo-point-type.html#_mapping_options[Elasticsearch geo_point].

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 map visualization).

NOTE

– This product includes GeoLite2 data created by MaxMind, available from www.maxmind.com. This database is licensed under creativecommons.org/licenses/by-sa/4.0/[Creative Commons Attribution-ShareAlike 4.0 International License].

Versions 4.0.0 and later of the GeoIP filter use the MaxMind GeoLite2 database and support both IPv4 and IPv6 lookups. Versions prior to 4.0.0 use the legacy MaxMind GeoLite database and support IPv4 lookups only. –

Constant Summary collapse

ECS_TARGET_FIELD =
%w{
  client
  destination
  host
  observer
  server
  source
}.map(&:freeze).freeze
MINIMUM_LOGSTASH_VERSION =
">= 7.14.0".freeze

Instance Method Summary collapse

Instance Method Details

#auto_target_from_source!Object



140
141
142
143
144
145
# File 'lib/logstash/filters/geoip.rb', line 140

def auto_target_from_source!
  return @source[0...-4] if @source.end_with?('[ip]') && @source.length > 4

  fail(LogStash::ConfigurationError, "GeoIP Filter in ECS-Compatiblity mode "\
                                     "requires a `target` when `source` is not an `ip` sub-field, eg. [client][ip]")
end

#closeObject



173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/logstash/filters/geoip.rb', line 173

def close
  begin
    @database_manager.unsubscribe_database_path(@default_database_type, self) if @database_manager
  rescue => e
    @logger.error("Error unsubscribing geoip database path", :path => @database, :exception => e)
  end

  begin
    @geoipfilter.close if @geoipfilter
  rescue => e
    @logger.error("Error closing GeoIPFilter",  :exception => e)
  end
end

#compatible_logstash_version?Boolean

Returns:

  • (Boolean)


212
213
214
# File 'lib/logstash/filters/geoip.rb', line 212

def compatible_logstash_version?
  Gem::Requirement.new(MINIMUM_LOGSTASH_VERSION).satisfied_by?(Gem::Version.new(LOGSTASH_VERSION))
end

#fail_filterObject



169
170
171
# File 'lib/logstash/filters/geoip.rb', line 169

def fail_filter
  @healthy_database = false
end

#filter(event) ⇒ Object



113
114
115
116
117
118
119
120
121
122
# File 'lib/logstash/filters/geoip.rb', line 113

def filter(event)
  return unless filter?(event)
  return event.tag("_geoip_expired_database") unless @healthy_database

  if @geoipfilter.handleEvent(event)
    filter_matched(event)
  else
    tag_unsuccessful_lookup(event)
  end
end

#load_database_manager?Boolean

Returns:

  • (Boolean)


201
202
203
204
205
206
207
208
209
# File 'lib/logstash/filters/geoip.rb', line 201

def load_database_manager?
  begin
    require_relative ::File.join(LogStash::Environment::LOGSTASH_HOME, "x-pack", "lib", "filters", "geoip", "database_manager")
    compatible_logstash_version?
  rescue LoadError => e
    @logger.info("DatabaseManager is not in classpath", :version => LOGSTASH_VERSION, :exception => e)
    false
  end
end

#registerObject



107
108
109
110
# File 'lib/logstash/filters/geoip.rb', line 107

def register
  setup_target_field
  setup_filter(select_database_path)
end

#select_database_pathObject



187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/logstash/filters/geoip.rb', line 187

def select_database_path
  path =
    if load_database_manager?
      @database_manager = LogStash::Filters::Geoip::DatabaseManager.instance
      @database_manager.subscribe_database_path(@default_database_type, @database, self)
    else
      vendor_path = ::File.expand_path(::File.join("..", "..", "..", "..", "vendor"), __FILE__)
      @database.nil? ? ::File.join(vendor_path, "GeoLite2-#{@default_database_type}.mmdb") : @database
    end

  @logger.info("Using geoip database", :path => path)
  path
end

#setup_filter(database_path) ⇒ Object



147
148
149
150
151
152
153
# File 'lib/logstash/filters/geoip.rb', line 147

def setup_filter(database_path)
  @healthy_database = !database_path.nil?
  return if database_path.nil?

  @database = database_path
  @geoipfilter = org.logstash.filters.geoip.GeoIPFilter.new(@source, @target, @fields, @database, @cache_size, ecs_compatibility.to_s)
end

#setup_target_fieldObject



129
130
131
132
133
134
135
136
137
138
# File 'lib/logstash/filters/geoip.rb', line 129

def setup_target_field
  if ecs_compatibility == :disabled
    @target ||= 'geoip'
  else
    @target ||= auto_target_from_source!
    # normalize top-level fields to not be bracket-wrapped
    normalized_target = @target.gsub(/\A\[([^\[\]]+)\]\z/,'\1')
    logger.warn("ECS expect `target` value `#{normalized_target}` in #{ECS_TARGET_FIELD}") unless ECS_TARGET_FIELD.include?(normalized_target)
  end
end

#tag_unsuccessful_lookup(event) ⇒ Object



124
125
126
127
# File 'lib/logstash/filters/geoip.rb', line 124

def tag_unsuccessful_lookup(event)
  @logger.debug? && @logger.debug("IP #{event.get(@source)} was not found in the database", :event => event)
  @tag_on_failure.each{|tag| event.tag(tag)}
end

#update_filter(action, *args) ⇒ Object

call by DatabaseManager



156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/logstash/filters/geoip.rb', line 156

def update_filter(action, *args)
  @logger.trace("update filter", :action => action, :args => args) if @logger.trace?

  case action
  when :update
    setup_filter(*args)
  when :expire
    fail_filter
  else
    @logger.warn("invalid action: #{action}")
  end
end