logstash-filter-geoip 7.0.1-java → 7.1.0-java

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3775b623a8def0e1d46ab786bb0d386f38fe2f6db3cc52adf5d2cf271bc6441c
4
- data.tar.gz: a3edac69f8071574af6bf2d8456bb63cda66874f8a8c9f5d2e5867cfeb4bc100
3
+ metadata.gz: d3997f6af427481c6a4b2831a3253a98609c0105054182fd32ad7a1815497072
4
+ data.tar.gz: 6e9ba6c58d7ccfa8049a8702018422441e003607633072ad6359c700b8dce8ed
5
5
  SHA512:
6
- metadata.gz: 20030a899125bda090747d654c48e152690ca34203e08e11e3d380202dc79629c8da3e42fc238845568d672321711d565ca9235ad60f2a941d09dc598be3be55
7
- data.tar.gz: de3c227f96dfc13b18d7e2397af48193f1b26274384049f8037ab7f07e401727523cf60ca233fab18aaeb855aa5c34760df7c9357b8303f2fb7e877529f50953
6
+ metadata.gz: 44d7f9debe16a4245b7044b4dba632d1478f5216852b5ae0d2a919e797dce0d06c080a27bf82c081295819a84fd86dd3931ddc626a344624529c9255ac3dc645
7
+ data.tar.gz: 929c2867ab360f704123daac8536ec1f5775bd0081ba797bf563111a9ac40729f94b269e026e2f11d8367e7f3d59f446868f57ace6ddee34cb992fc5420de786
data/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ ## 7.1.0
2
+ - Add ECS compatibility [#179](https://github.com/logstash-plugins/logstash-filter-geoip/pull/179)
3
+
1
4
  ## 7.0.1
2
5
  - [DOC] Add documentation for MaxMind database license change [#177](https://github.com/logstash-plugins/logstash-filter-geoip/pull/177)
3
6
 
data/docs/index.asciidoc CHANGED
@@ -92,6 +92,7 @@ This plugin supports the following configuration options plus the <<plugins-{typ
92
92
  | <<plugins-{type}s-{plugin}-cache_size>> |<<number,number>>|No
93
93
  | <<plugins-{type}s-{plugin}-database>> |a valid filesystem path|No
94
94
  | <<plugins-{type}s-{plugin}-default_database_type>> |`City` or `ASN`|No
95
+ | <<plugins-{type}s-{plugin}-ecs_compatibility>> | <<string,string>>|No
95
96
  | <<plugins-{type}s-{plugin}-fields>> |<<array,array>>|No
96
97
  | <<plugins-{type}s-{plugin}-source>> |<<string,string>>|Yes
97
98
  | <<plugins-{type}s-{plugin}-tag_on_failure>> |<<array,array>>|No
@@ -161,9 +162,23 @@ are included in the event.
161
162
 
162
163
  For the built-in GeoLite2 City database, the following are available:
163
164
  `city_name`, `continent_code`, `country_code2`, `country_code3`, `country_name`,
164
- `dma_code`, `ip`, `latitude`, `longitude`, `postal_code`, `region_code`,
165
+ `dma_code`, `ip`, `latitude`, `location`, `longitude`, `postal_code`, `region_code`,
165
166
  `region_name` and `timezone`.
166
167
 
168
+ [id="plugins-{type}s-{plugin}-ecs_compatibility"]
169
+ ===== `ecs_compatibility`
170
+
171
+ * Value type is <<string,string>>
172
+ * Supported values are:
173
+ ** `disabled`: unstructured geo data added at root level
174
+ ** `v1`: uses fields that are compatible with Elastic Common Schema (for example, `[client][geo][country_name]`)
175
+ * Default value depends on which version of Logstash is running:
176
+ ** When Logstash provides a `pipeline.ecs_compatibility` setting, its value is used as the default
177
+ ** Otherwise, the default value is `disabled`.
178
+
179
+ Controls this plugin's compatibility with the {ecs-ref}[Elastic Common Schema (ECS)].
180
+ The value of this setting affects the _default_ value of <<plugins-{type}s-{plugin}-target>>.
181
+
167
182
  [id="plugins-{type}s-{plugin}-source"]
168
183
  ===== `source`
169
184
 
@@ -185,8 +200,15 @@ Tags the event on failure to look up geo information. This can be used in later
185
200
  [id="plugins-{type}s-{plugin}-target"]
186
201
  ===== `target`
187
202
 
203
+ * This is an optional setting with condition.
188
204
  * Value type is <<string,string>>
189
- * Default value is `"geoip"`
205
+ * Default value depends on whether <<plugins-{type}s-{plugin}-ecs_compatibility>> is enabled:
206
+ ** ECS Compatibility disabled: `geoip`
207
+ ** ECS Compatibility enabled: If `source` is an `ip` sub-field, eg. `[client][ip]`,
208
+ `target` will automatically set to the parent field, in this example `client`,
209
+ otherwise, `target` is a required setting
210
+ *** `geo` field is nested in `[client][geo]`
211
+ *** ECS compatible values are `client`, `destination`, `host`, `observer`, `server`, `source`
190
212
 
191
213
  Specify the field into which Logstash should store the geoip data.
192
214
  This can be useful, for example, if you have `src_ip` and `dst_ip` fields and
@@ -2,6 +2,7 @@
2
2
  require "logstash/filters/base"
3
3
  require "logstash/namespace"
4
4
  require "logstash-filter-geoip_jars"
5
+ require "logstash/plugin_mixins/ecs_compatibility_support"
5
6
 
6
7
 
7
8
  # The GeoIP filter adds information about the geographical location of IP addresses,
@@ -31,6 +32,8 @@ require "logstash-filter-geoip_jars"
31
32
  # --
32
33
 
33
34
  class LogStash::Filters::GeoIP < LogStash::Filters::Base
35
+ include LogStash::PluginMixins::ECSCompatibilitySupport(:disabled, :v1)
36
+
34
37
  config_name "geoip"
35
38
 
36
39
  # The path to the GeoLite2 database file which Logstash should use. City and ASN databases are supported.
@@ -60,14 +63,16 @@ class LogStash::Filters::GeoIP < LogStash::Filters::Base
60
63
  # This can be useful, for example, if you have `src_ip` and `dst_ip` fields and
61
64
  # would like the GeoIP information of both IPs.
62
65
  #
63
- # If you save the data to a target field other than `geoip` and want to use the
64
- # `geo_point` related functions in Elasticsearch, you need to alter the template
65
- # provided with the Elasticsearch output and configure the output to use the
66
- # new template.
66
+ # ECS disabled/ Legacy default: `geoip`
67
+ # ECS default: The `target` is auto-generated from `source` when the `source` specifies an `ip` sub-field
68
+ # For example, source => [client][ip], `target` will be `client`
69
+ # If `source` is not an `ip` sub-field, source => client_ip, `target` setting is mandatory
70
+ #
71
+ # Elasticsearch ECS mode expected `geo` fields to be nested at:
72
+ # `client`, `destination`, `host`, `observer`, `server`, `source`
67
73
  #
68
- # Even if you don't use the `geo_point` mapping, the `[target][location]` field
69
- # is still valid GeoJSON.
70
- config :target, :validate => :string, :default => 'geoip'
74
+ # `geo` fields are not expected to be used directly at the root of the events
75
+ config :target, :validate => :string
71
76
 
72
77
  # GeoIP lookup is surprisingly expensive. This filter uses an cache to take advantage of the fact that
73
78
  # IPs agents are often found adjacent to one another in log files and rarely have a random distribution.
@@ -89,7 +94,18 @@ class LogStash::Filters::GeoIP < LogStash::Filters::Base
89
94
  config :tag_on_failure, :validate => :array, :default => ["_geoip_lookup_failure"]
90
95
 
91
96
  public
97
+
98
+ ECS_TARGET_FIELD = %w{
99
+ client
100
+ destination
101
+ host
102
+ observer
103
+ server
104
+ source
105
+ }.map(&:freeze).freeze
106
+
92
107
  def register
108
+ setup_target_field
93
109
  setup_filter(select_database_path)
94
110
  end
95
111
 
@@ -108,10 +124,29 @@ class LogStash::Filters::GeoIP < LogStash::Filters::Base
108
124
  @tag_on_failure.each{|tag| event.tag(tag)}
109
125
  end
110
126
 
127
+ def setup_target_field
128
+ if ecs_compatibility == :disabled
129
+ @target ||= 'geoip'
130
+ else
131
+ @target ||= auto_target_from_source!
132
+ # normalize top-level fields to not be bracket-wrapped
133
+ normalized_target = @target.gsub(/\A\[([^\[\]]+)\]\z/,'\1')
134
+ logger.warn("ECS expect `target` value `#{normalized_target}` in #{ECS_TARGET_FIELD}") unless ECS_TARGET_FIELD.include?(normalized_target)
135
+ end
136
+ end
137
+
138
+ def auto_target_from_source!
139
+ return @source[0...-4] if @source.end_with?('[ip]') && @source.length > 4
140
+
141
+ fail(LogStash::ConfigurationError, "GeoIP Filter in ECS-Compatiblity mode "\
142
+ "requires a `target` when `source` is not an `ip` sub-field, eg. [client][ip]")
143
+ end
144
+
145
+
111
146
  def setup_filter(database_path)
112
147
  @database = database_path
113
148
  @logger.info("Using geoip database", :path => @database)
114
- @geoipfilter = org.logstash.filters.GeoIPFilter.new(@source, @target, @fields, @database, @cache_size)
149
+ @geoipfilter = org.logstash.filters.geoip.GeoIPFilter.new(@source, @target, @fields, @database, @cache_size, ecs_compatibility.to_s)
115
150
  end
116
151
 
117
152
  def terminate_filter
@@ -125,7 +160,7 @@ class LogStash::Filters::GeoIP < LogStash::Filters::Base
125
160
  end
126
161
 
127
162
  def select_database_path
128
- vendor_path = ::File.expand_path("../../../vendor/", ::File.dirname(__FILE__))
163
+ vendor_path = ::File.expand_path(::File.join("..", "..", "..", "..", "vendor"), __FILE__)
129
164
 
130
165
  if load_database_manager?
131
166
  @database_manager = LogStash::Filters::Geoip::DatabaseManager.new(self, @database, @default_database_type, vendor_path)
@@ -137,7 +172,7 @@ class LogStash::Filters::GeoIP < LogStash::Filters::Base
137
172
 
138
173
  def load_database_manager?
139
174
  begin
140
- require_relative "#{LogStash::Environment::LOGSTASH_HOME}/x-pack/lib/filters/geoip/database_manager"
175
+ require_relative ::File.join(LogStash::Environment::LOGSTASH_HOME, "x-pack", "lib", "filters", "geoip", "database_manager")
141
176
  true
142
177
  rescue LoadError => e
143
178
  @logger.info("DatabaseManager is not in classpath", :version => LOGSTASH_VERSION, :exception => e)
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
 
3
3
  s.name = 'logstash-filter-geoip'
4
- s.version = '7.0.1'
4
+ s.version = '7.1.0'
5
5
  s.licenses = ['Apache License (2.0)']
6
6
  s.summary = "Adds geographical information about an IP address"
7
7
  s.description = "This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This gem is not a stand-alone program"
@@ -22,6 +22,7 @@ Gem::Specification.new do |s|
22
22
 
23
23
  # Gem dependencies
24
24
  s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99"
25
+ s.add_runtime_dependency 'logstash-mixin-ecs_compatibility_support', '~>1.1'
25
26
  s.add_development_dependency 'logstash-devutils'
26
27
  s.add_development_dependency 'insist'
27
28
  s.add_development_dependency 'benchmark-ips'
@@ -0,0 +1,203 @@
1
+ # encoding: utf-8
2
+ require "logstash/devutils/rspec/spec_helper"
3
+ require "logstash/filters/geoip"
4
+ require_relative 'test_helper'
5
+ require 'logstash/plugin_mixins/ecs_compatibility_support/spec_helper'
6
+
7
+ CITYDB = ::Dir.glob(::File.expand_path(::File.join("..", "..", "..", "vendor", "GeoLite2-City.mmdb"), __FILE__)).first
8
+ ASNDB = ::Dir.glob(::File.expand_path(::File.join("..", "..", "..", "vendor", "GeoLite2-ASN.mmdb"), __FILE__)).first
9
+
10
+ describe LogStash::Filters::GeoIP do
11
+ let(:options) { {} }
12
+ let(:plugin) { LogStash::Filters::GeoIP.new(options) }
13
+
14
+ describe "simple ip filter", :aggregate_failures do
15
+
16
+ context "when specifying the target", :ecs_compatibility_support do
17
+ ecs_compatibility_matrix(:disabled, :v1) do |ecs_select|
18
+
19
+ let(:ip) { "8.8.8.8" }
20
+ let(:event) { LogStash::Event.new("message" => ip) }
21
+ let(:target) { "server" }
22
+ let(:common_options) { {"source" => "message", "database" => CITYDB, "target" => target} }
23
+
24
+ before(:each) do
25
+ allow_any_instance_of(described_class).to receive(:ecs_compatibility).and_return(ecs_compatibility)
26
+ plugin.register
27
+ end
28
+
29
+ context "with city database" do
30
+ let(:options) { common_options }
31
+
32
+ it "should return geo in target" do
33
+ plugin.filter(event)
34
+
35
+ expect( event.get ecs_select[disabled: "[#{target}][ip]", v1: "[#{target}][ip]"] ).to eq ip
36
+ expect( event.get ecs_select[disabled: "[#{target}][country_code2]", v1: "[#{target}][geo][country_iso_code]"] ).to eq 'US'
37
+ expect( event.get ecs_select[disabled: "[#{target}][country_name]", v1: "[#{target}][geo][country_name]"] ).to eq 'United States'
38
+ expect( event.get ecs_select[disabled: "[#{target}][continent_code]", v1: "[#{target}][geo][continent_code]"] ).to eq 'NA'
39
+ expect( event.get ecs_select[disabled: "[#{target}][location][lat]", v1: "[#{target}][geo][location][lat]"] ).to eq 37.751
40
+ expect( event.get ecs_select[disabled: "[#{target}][location][lon]", v1: "[#{target}][geo][location][lon]"] ).to eq -97.822
41
+
42
+ if ecs_select.active_mode == :disabled
43
+ expect( event.get "[#{target}][country_code3]" ).to eq 'US'
44
+ else
45
+ expect( event.get "[#{target}][geo][country_code3]" ).to be_nil
46
+ expect( event.get "[#{target}][country_code3]" ).to be_nil
47
+ end
48
+ end
49
+ end
50
+
51
+
52
+ context "with ASN database" do
53
+ let(:options) { common_options.merge({"database" => ASNDB}) }
54
+
55
+ it "should return geo in target" do
56
+ plugin.filter(event)
57
+
58
+ expect( event.get ecs_select[disabled: "[#{target}][ip]", v1: "[#{target}][ip]"] ).to eq ip
59
+ expect( event.get ecs_select[disabled: "[#{target}][asn]", v1: "[#{target}][as][number]"] ).to eq 15169
60
+ expect( event.get ecs_select[disabled: "[#{target}][as_org]", v1: "[#{target}][as][organization][name]"] ).to eq "Google LLC"
61
+ end
62
+ end
63
+
64
+ context "with customize fields" do
65
+ let(:fields) { ["continent_name", "timezone"] }
66
+ let(:options) { common_options.merge({"fields" => fields}) }
67
+
68
+ it "should return fields" do
69
+ plugin.filter(event)
70
+
71
+ expect( event.get ecs_select[disabled: "[#{target}][ip]", v1: "[#{target}][ip]"] ).to be_nil
72
+ expect( event.get ecs_select[disabled: "[#{target}][country_code2]", v1: "[#{target}][geo][country_iso_code]"] ).to be_nil
73
+ expect( event.get ecs_select[disabled: "[#{target}][country_name]", v1: "[#{target}][geo][country_name]"] ).to be_nil
74
+ expect( event.get ecs_select[disabled: "[#{target}][continent_code]", v1: "[#{target}][geo][continent_code]"] ).to be_nil
75
+ expect( event.get ecs_select[disabled: "[#{target}][location][lat]", v1: "[#{target}][geo][location][lat]"] ).to be_nil
76
+ expect( event.get ecs_select[disabled: "[#{target}][location][lon]", v1: "[#{target}][geo][location][lon]"] ).to be_nil
77
+
78
+ expect( event.get ecs_select[disabled: "[#{target}][continent_name]", v1: "[#{target}][geo][continent_name]"] ).to eq "North America"
79
+ expect( event.get ecs_select[disabled: "[#{target}][timezone]", v1: "[#{target}][geo][timezone]"] ).to eq "America/Chicago"
80
+ end
81
+ end
82
+
83
+ end
84
+ end
85
+
86
+ context "setup target field" do
87
+ let(:ip) { "8.8.8.8" }
88
+ let(:event) { LogStash::Event.new("message" => ip) }
89
+ let(:common_options) { {"source" => "message", "database" => CITYDB} }
90
+
91
+ context "ECS disabled" do
92
+ before do
93
+ allow_any_instance_of(described_class).to receive(:ecs_compatibility).and_return(:disabled)
94
+ plugin.register
95
+ plugin.filter(event)
96
+ end
97
+
98
+ context "`target` is unset" do
99
+ let(:options) { common_options }
100
+ it "should use 'geoip'" do
101
+ expect( event.get "[geoip][ip]" ).to eq ip
102
+ end
103
+ end
104
+
105
+ context "`target` is set" do
106
+ let(:target) { 'host' }
107
+ let(:options) { common_options.merge({"target" => target}) }
108
+ it "should use `target`" do
109
+ expect( event.get "[#{target}][ip]" ).to eq ip
110
+ end
111
+ end
112
+ end
113
+
114
+ context "ECS mode" do
115
+ before do
116
+ allow_any_instance_of(described_class).to receive(:ecs_compatibility).and_return(:v1)
117
+ end
118
+
119
+ context "`target` is unset" do
120
+
121
+ context "`source` end with [ip]" do
122
+ let(:event) { LogStash::Event.new("host" => {"ip" => ip}) }
123
+ let(:options) { common_options.merge({"source" => "[host][ip]"}) }
124
+
125
+ it "should use source's parent as target" do
126
+ plugin.register
127
+ plugin.filter(event)
128
+ expect( event.get "[host][geo][country_iso_code]" ).to eq 'US'
129
+ end
130
+ end
131
+
132
+ context "`source` end with [ip] but `target` does not match ECS template" do
133
+ let(:event) { LogStash::Event.new("hostname" => {"ip" => ip}) }
134
+ let(:options) { common_options.merge({"source" => "[hostname][ip]"}) }
135
+
136
+ it "should use source's parent as target with warning" do
137
+ expect(plugin.logger).to receive(:warn).with(/ECS expect `target`/)
138
+ plugin.register
139
+ plugin.filter(event)
140
+ expect( event.get "[hostname][geo][country_iso_code]" ).to eq 'US'
141
+ end
142
+ end
143
+
144
+ context "`source` == [ip]" do
145
+ let(:event) { LogStash::Event.new("ip" => ip) }
146
+ let(:options) { common_options.merge({"source" => "[ip]"}) }
147
+
148
+ it "should raise error to require `target`" do
149
+ expect { plugin.register }.to raise_error LogStash::ConfigurationError, /requires a `target`/
150
+ end
151
+ end
152
+
153
+ context "`source` not end with [ip]" do
154
+ let(:event) { LogStash::Event.new("host_ip" => ip) }
155
+ let(:options) { common_options.merge({"source" => "host_ip"}) }
156
+
157
+ it "should raise error to require `target`" do
158
+ expect { plugin.register }.to raise_error LogStash::ConfigurationError, /requires a `target`/
159
+ end
160
+ end
161
+ end
162
+
163
+ context "`target` is set" do
164
+ let(:event) { LogStash::Event.new("client" => {"ip" => ip}) }
165
+ let(:options) { common_options.merge({"source" => "[client][ip]", "target" => target}) }
166
+
167
+ context "`target` matches ECS template" do
168
+ let(:target) { 'host' }
169
+
170
+ it "should use `target`" do
171
+ plugin.register
172
+ plugin.filter(event)
173
+ expect( event.get "[#{target}][geo][country_iso_code]" ).to eq 'US'
174
+ end
175
+ end
176
+
177
+ context "`target` in canonical field reference syntax matches ECS template" do
178
+ let(:target) { '[host]' }
179
+
180
+ it "should normalize and use `target`" do
181
+ expect(plugin.logger).to receive(:warn).never
182
+ plugin.register
183
+ plugin.filter(event)
184
+ expect( event.get "[host][geo][country_iso_code]" ).to eq 'US'
185
+ end
186
+ end
187
+
188
+ context "`target` does not match ECS template" do
189
+ let(:target) { 'host_ip' }
190
+
191
+ it "should use `target` with warning" do
192
+ expect(plugin.logger).to receive(:warn).with(/ECS expect `target`/)
193
+ plugin.register
194
+ plugin.filter(event)
195
+ expect( event.get "[#{target}][geo][country_iso_code]" ).to eq 'US'
196
+ end
197
+ end
198
+ end
199
+ end
200
+ end
201
+
202
+ end
203
+ end
@@ -3,8 +3,8 @@ require "logstash/devutils/rspec/spec_helper"
3
3
  require "insist"
4
4
  require "logstash/filters/geoip"
5
5
 
6
- CITYDB = ::Dir.glob(::File.expand_path("../../vendor/", ::File.dirname(__FILE__))+"/GeoLite2-City.mmdb").first
7
- ASNDB = ::Dir.glob(::File.expand_path("../../vendor/", ::File.dirname(__FILE__))+"/GeoLite2-ASN.mmdb").first
6
+ CITYDB = ::Dir.glob(::File.expand_path(::File.join("..", "..", "..", "vendor", "GeoLite2-City.mmdb"), __FILE__)).first
7
+ ASNDB = ::Dir.glob(::File.expand_path(::File.join("..", "..", "..", "vendor", "GeoLite2-ASN.mmdb"), __FILE__)).first
8
8
 
9
9
  describe LogStash::Filters::GeoIP do
10
10
  describe "defaults" do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstash-filter-geoip
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.0.1
4
+ version: 7.1.0
5
5
  platform: java
6
6
  authors:
7
7
  - Elastic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-03-11 00:00:00.000000000 Z
11
+ date: 2021-03-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -30,6 +30,20 @@ dependencies:
30
30
  - - "<="
31
31
  - !ruby/object:Gem::Version
32
32
  version: '2.99'
33
+ - !ruby/object:Gem::Dependency
34
+ requirement: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - "~>"
37
+ - !ruby/object:Gem::Version
38
+ version: '1.1'
39
+ name: logstash-mixin-ecs_compatibility_support
40
+ prerelease: false
41
+ type: :runtime
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.1'
33
47
  - !ruby/object:Gem::Dependency
34
48
  requirement: !ruby/object:Gem::Requirement
35
49
  requirements:
@@ -92,6 +106,7 @@ files:
92
106
  - lib/logstash/filters/geoip/patch.rb
93
107
  - logstash-filter-geoip.gemspec
94
108
  - maxmind-db-NOTICE.txt
109
+ - spec/filters/geoip_ecs_spec.rb
95
110
  - spec/filters/geoip_offline_spec.rb
96
111
  - spec/filters/geoip_online_spec.rb
97
112
  - spec/filters/geoip_spec.rb
@@ -129,6 +144,7 @@ signing_key:
129
144
  specification_version: 4
130
145
  summary: Adds geographical information about an IP address
131
146
  test_files:
147
+ - spec/filters/geoip_ecs_spec.rb
132
148
  - spec/filters/geoip_offline_spec.rb
133
149
  - spec/filters/geoip_online_spec.rb
134
150
  - spec/filters/geoip_spec.rb