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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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