fluent-plugin-geoip 1.2.0 → 1.3.0

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: 3a88a41e91e927825689d485148e6d1369532f01f2bc3395d76204c98f02366f
4
- data.tar.gz: 984c8db424d319565862de808844432366f38d00b2cd1c6b617d4ead0d77af8f
3
+ metadata.gz: eab0d5c4f07207bfeba15ba4c11ba6b9d4acc8538235e6b2820e7207817803cb
4
+ data.tar.gz: 549a11f6f954945e37301b0cc010d8272193768a81e198f474552327e0d304ec
5
5
  SHA512:
6
- metadata.gz: 0f48ad83f7b2ed7d47bd7822042e546cd1f0b6503d71c3175c07ccdc84fbfa21fdafc960187a40b5cd39d85636e256b09ba69ff69972ef5806bf3aa746d6ef82
7
- data.tar.gz: 1ee9ce806e3bf90c1fac1657bc09ad1abfac5033ce6ac1f79b78fe6d374caab45b2fcb3eb3812ccae34124da2e861bd9e65f19dbac4574ae4d3db637bff3e567
6
+ metadata.gz: 7380799ed242d60ee4281870b8c2b23261428f02b5d4aa1b2908039219659fa8730b596b4713f09da6ea3c63d96e7795f7420ce0c62142f29e4542c13eb32706
7
+ data.tar.gz: 737f87472b5d5e145294067be686b51b984433d9d360265fef59da0afa93a21d77a12db4612af0b4d3183c4439b33eebcf47e1ab5fd98a23f8e7701152adee30
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # fluent-plugin-geoip [![Build Status](https://travis-ci.org/y-ken/fluent-plugin-geoip.png?branch=master)](https://travis-ci.org/y-ken/fluent-plugin-geoip)
2
2
 
3
- Fluentd Filter/Output plugin to add information about geographical location of IP addresses with Maxmind GeoIP databases.
3
+ Fluentd Filter plugin to add information about geographical location of IP addresses with Maxmind GeoIP databases.
4
4
 
5
5
  fluent-plugin-geoip has bundled cost-free [GeoLite2 Free Downloadable Databases](https://dev.maxmind.com/geoip/geoip2/geolite2/) and [GeoLite City database](http://dev.maxmind.com/geoip/legacy/geolite/) by default.<br />
6
6
  Also you can use purchased [GeoIP City database](http://www.maxmind.com/en/city) ([lang:ja](http://www.maxmind.com/ja/city)) which costs starting from $50.
@@ -21,56 +21,7 @@ If you want to use this plugin with Fluentd v0.12.x or earlier use 0.8.x.
21
21
 
22
22
  ### Compatibility notice
23
23
 
24
- We've used Fluentd v1 API in this plugin since 1.0.0.
25
- So we have dropped some features from GeoipOutput.
26
-
27
- See also [official document](http://docs.fluentd.org/v1.0/articles/plugin-update-from-v12)
28
-
29
- #### Fluent::Mixin::RewriteTagName
30
-
31
- * `${tag}`, `__TAG__`
32
-
33
- Alternative: Use `${tag}` placeholder
34
-
35
- * `${tag_parts[n]}`, `__TAG_PARTS[n]__`
36
-
37
- Alternative: Use `${tag[n]}` placeholder
38
-
39
- * `${hostname}`, `__HOSTNAME__`
40
-
41
- Alternative1: Use filter before this plugin and chunk keys:
42
- ```
43
- <filter>
44
- @type record_transformer
45
- <record>
46
- hostname ${hostname}
47
- </record>
48
- </filter>
49
- <match **>
50
- @type geoip
51
- tag geoip.${tag[1]}.${hostname}
52
- <record>
53
- city ${city["host"]}
54
- </record>
55
- <buffer tag, hostname>
56
- flush_interval 1s
57
- </buffer>
58
- </match>
59
- ```
60
-
61
- Alternative2: Just inject hostname into record you can use `<inject>` section instead:
62
- ```
63
- <match **>
64
- @type geoip
65
- tag geoip.${tag[1]}.${hostname}
66
- <record>
67
- city ${city["host"]}
68
- </record>
69
- <inject>
70
- hostname_key hostname
71
- </inject>
72
- </match>
73
- ```
24
+ We've removed GeoipOutput since 1.3.0, because GeoipFilter is enough to add information about geographical location of IP addresse.
74
25
 
75
26
  ## Dependency
76
27
 
@@ -90,6 +41,8 @@ $ brew install geoip
90
41
  $ bundle config build.geoip-c --with-geoip-dir=/usr/local/include/
91
42
  ```
92
43
 
44
+ See [geoip2_c](https://github.com/okkez/geoip2_c#build-requirements), if you failed to install geoip2_c.
45
+
93
46
  ## Installation
94
47
 
95
48
  install with `gem` or td-agent provided command as:
@@ -116,7 +69,6 @@ Note that filter version of geoip plugin does not have handling tag feature.
116
69
  @type geoip
117
70
 
118
71
  # Specify one or more geoip lookup field which has ip address (default: host)
119
- # in the case of accessing nested value, delimit keys by dot like 'host.ip'.
120
72
  geoip_lookup_keys host
121
73
 
122
74
  # Specify optional geoip database (using bundled GeoLiteCity databse by default)
@@ -157,6 +109,92 @@ Note that filter version of geoip plugin does not have handling tag feature.
157
109
  </filter>
158
110
  ```
159
111
 
112
+ #### Tips: Modify records without city information
113
+
114
+ ```
115
+ <filter access.apache>
116
+ @type geoip
117
+ geoip_lookup_keys remote_addr
118
+ <record>
119
+ city ${city.names.en["remote_addr"]} # skip adding fields if this field is null
120
+ latitude ${location.latitude["remote_addr"]}
121
+ longitude ${location.longitude["remote_addr"]}
122
+ country ${country.iso_code["remote_addr"]}
123
+ country_name ${country.names.en["remote_addr"]}
124
+ postal_code ${postal.code["remote_addr"]}
125
+ </record>
126
+ skip_adding_null_record true
127
+ </filter>
128
+ ```
129
+
130
+ Skip adding fields if incoming `remote_addr`'s GeoIP data is like following:
131
+
132
+ ```ruby
133
+ # the record does not have "city" field
134
+ {"continent"=>
135
+ {"code"=>"NA",
136
+ "geoname_id"=>6255149,
137
+ "names"=>
138
+ {"de"=>"Nordamerika",
139
+ "en"=>"North America",
140
+ "es"=>"Norteamérica",
141
+ "fr"=>"Amérique du Nord",
142
+ "ja"=>"北アメリカ",
143
+ "pt-BR"=>"América do Norte",
144
+ "ru"=>"Северная Америка",
145
+ "zh-CN"=>"北美洲"}},
146
+ "country"=>
147
+ {"geoname_id"=>6252001,
148
+ "iso_code"=>"US",
149
+ "names"=>
150
+ {"de"=>"USA",
151
+ "en"=>"United States",
152
+ "es"=>"Estados Unidos",
153
+ "fr"=>"États-Unis",
154
+ "ja"=>"アメリカ合衆国",
155
+ "pt-BR"=>"Estados Unidos",
156
+ "ru"=>"США",
157
+ "zh-CN"=>"美国"}},
158
+ "location"=>
159
+ {"accuracy_radius"=>1000, "latitude"=>37.751, "longitude"=>-97.822},
160
+ "registered_country"=>
161
+ {"geoname_id"=>6252001,
162
+ "iso_code"=>"US",
163
+ "names"=>
164
+ {"de"=>"USA",
165
+ "en"=>"United States",
166
+ "es"=>"Estados Unidos",
167
+ "fr"=>"États-Unis",
168
+ "ja"=>"アメリカ合衆国",
169
+ "pt-BR"=>"Estados Unidos",
170
+ "ru"=>"США",
171
+ "zh-CN"=>"美国"}}}
172
+ ```
173
+
174
+ We can avoid this behavior changing field order in `<record>` like following:
175
+
176
+ ```
177
+ <filter access.apache>
178
+ @type geoip
179
+ geoip_lookup_keys remote_addr
180
+ <record>
181
+ latitude ${location.latitude["remote_addr"]} # this field must not be null
182
+ longitude ${location.longitude["remote_addr"]}
183
+ country ${country.iso_code["remote_addr"]}
184
+ country_name ${country.names.en["remote_addr"]}
185
+ postal_code ${postal.code["remote_addr"]}
186
+ city ${city.names.en["remote_addr"]} # adding fields even if this field is null
187
+ </record>
188
+ skip_adding_null_record true
189
+ </filter>
190
+ ```
191
+
192
+ #### Tips: nested attributes for geoip_lookup_keys
193
+
194
+ See [Record Accessor Plugin](https://docs.fluentd.org/v1.0/articles/api-plugin-helper-record_accessor#syntax)
195
+
196
+ **NOTE** Since v1.3.0 does not interpret `host.ip` as nested attribute.
197
+
160
198
  #### Advanced config samples
161
199
 
162
200
  It is a sample to get friendly geo point recdords for elasticsearch with Yajl (JSON) parser.<br />
@@ -199,51 +237,6 @@ On the case of using td-agent3 (v1-config), it have to quote `{ ... }` or `[ ...
199
237
  </filter>
200
238
  ```
201
239
 
202
- ### For GeoipOutput
203
-
204
- ```xml
205
- <match access.apache>
206
- @type geoip
207
-
208
- # Specify one or more geoip lookup field which has ip address (default: host)
209
- # in the case of accessing nested value, delimit keys by dot like 'host.ip'.
210
- geoip_lookup_keys host
211
-
212
- # Specify optional geoip database (using bundled GeoLiteCity databse by default)
213
- geoip_database "/path/to/your/GeoIPCity.dat"
214
- # Specify optional geoip2 database
215
- # geoip2_database "/path/to/your/GeoLite2-City.mmdb"
216
- # Specify backend library (geoip, geoip2_compat, geoip2_c)
217
- backend_library geoip
218
-
219
- # Set adding field with placeholder (more than one settings are required.)
220
- <record>
221
- latitude ${location.latitude["host"]}
222
- longitude ${location.longitude["host"]}
223
- country ${country.iso_code["host"]}
224
- country_name ${country.names.en["host"]}
225
- postal_code ${postal.code["host"]}
226
- region ${subdivisions.0.iso_code["host"]}
227
- region_name ${subdivisions.0.names.en["host"]}
228
- city ${city.names.en["host"]}
229
- </record>
230
-
231
- # Settings for tag
232
- tag geoip.${tag[1]}
233
-
234
- # To avoid get stacktrace error with `[null, null]` array for elasticsearch.
235
- skip_adding_null_record true
236
-
237
- # Set @log_level (default: warn)
238
- @log_level info
239
-
240
- <buffer tag>
241
- # Set buffering time (default: 0s)
242
- flush_interval 1s
243
- </buffer>
244
- </match>
245
- ```
246
-
247
240
  ## Tutorial
248
241
 
249
242
  ### For GeoipFilter
@@ -255,7 +248,6 @@ On the case of using td-agent3 (v1-config), it have to quote `{ ... }` or `[ ...
255
248
  @type forward
256
249
  </source>
257
250
 
258
-
259
251
  <filter test.geoip>
260
252
  @type geoip
261
253
  geoip_lookup_keys host
@@ -290,57 +282,6 @@ $ bundle exec ruby urils/dump.rb geoip2_compat 66.102.3.80
290
282
  $ bundle exec ruby urils/dump.rb geoip 66.102.3.80
291
283
  ```
292
284
 
293
- ### For GeoipOutput
294
-
295
- #### configuration
296
-
297
- ```xml
298
- <source>
299
- @type forward
300
- </source>
301
-
302
- <match test.geoip>
303
- @type copy
304
- <store>
305
- @type stdout
306
- </store>
307
- <store>
308
- @type geoip
309
- geoip_lookup_keys host
310
- <record>
311
- lat ${location.latitude["host"]}
312
- lon ${location.longitude["host"]}
313
- country ${country.iso_code["host"]}
314
- </record>
315
- tag debug.${tag[1]}
316
- </store>
317
- </match>
318
-
319
- <match debug.**>
320
- @type stdout
321
- </match>
322
- ```
323
-
324
- #### result
325
-
326
- ```bash
327
- # forward record with Google's ip address.
328
- $ echo '{"host":"66.102.9.80","message":"test"}' | fluent-cat test.geoip
329
-
330
- # check the result at stdout
331
- $ tail /var/log/td-agent/td-agent.log
332
- 2013-08-04 16:21:32 +0900 test.geoip: {"host":"66.102.9.80","message":"test"}
333
- 2013-08-04 16:21:32 +0900 debug.geoip: {"host":"66.102.9.80","message":"test","lat":37.4192008972168,"lon":-122.05740356445312,"country":"US"}
334
- ```
335
-
336
- You can check geoip data format using [utils/dump.rb](https://github.com/okkez/fluent-plugin-geoip/utils/dump.rb).
337
-
338
- ```
339
- $ bundle exec ruby urils/dump.rb geoip2 66.102.3.80
340
- $ bundle exec ruby urils/dump.rb geoip2_compat 66.102.3.80
341
- $ bundle exec ruby urils/dump.rb geoip 66.102.3.80
342
- ```
343
-
344
285
  ## Placeholders
345
286
 
346
287
  ### GeoIP2
@@ -465,68 +406,6 @@ On the case of getting nothing of GeoIP info (such as local IP), it will output
465
406
 
466
407
  Set backend library.
467
408
 
468
- ### GeoipOutput
469
-
470
- #### Plugin helpers
471
-
472
- * [event_emitter](https://docs.fluentd.org/v1.0/articles/api-plugin-helper-event_emitter)
473
- * [compat_parameters](https://docs.fluentd.org/v1.0/articles/api-plugin-helper-compat_parameters)
474
- * [inject](https://docs.fluentd.org/v1.0/articles/api-plugin-helper-inject)
475
-
476
- See also [Output Plugin Overview](https://docs.fluentd.org/v1.0/articles/output-plugin-overview)
477
-
478
- #### Sections
479
-
480
- * [Inject section configurations](https://docs.fluentd.org/v1.0/articles/inject-section)
481
- * [Buffer section configurations](https://docs.fluentd.org/v1.0/articles/buffer-section)
482
-
483
- #### Parameters
484
-
485
- [Plugin Common Paramteters](https://docs.fluentd.org/v1.0/articles/plugin-common-parameters)
486
-
487
- **geoip_database** (string) (optional)
488
-
489
- * Default value: bundled database `GeoLiteCity.dat`
490
-
491
- Path to GeoIP database file.
492
-
493
- **geoip2_database** (string) (optional)
494
-
495
- * Default value: bundled database `GeoLite2-City.mmdb`.
496
-
497
- Path to GeoIP2 database file.
498
-
499
- **geoip_lookup_keys** (array) (optional)
500
-
501
- * Default value: `["host"]`
502
-
503
- Specify one or more geoip lookup field which has IP address.
504
-
505
- **geoip_lookup_key** (string) (optional) (deprecated)
506
-
507
- * Default value: `nil`.
508
-
509
- Use geoip_lookup_keys instead.
510
-
511
- **skip_adding_null_record** (bool) (optional)
512
-
513
- * Default value: `nil`
514
-
515
- Skip adding geoip fields when this valaues to `true`.
516
- On the case of getting nothing of GeoIP info (such as local IP), it will output the original record without changing anything.
517
-
518
- **backend_library** (enum) (optional)
519
-
520
- * Available values: `geoip`, `geoip2_compat`, `geoip2_c`
521
- * Default value: `geoip2_c`.
522
-
523
- Set backend library.
524
-
525
- **tag** (string) (optional)
526
-
527
- On using this option with tag placeholder like `tag geoip.${tag}` (test code is available at [test_out_geoip.rb](https://github.com/y-ken/fluent-plugin-geoip/blob/master/test/plugin/test_out_geoip.rb)).
528
-
529
-
530
409
  ## Articles
531
410
 
532
411
  * [IPアドレスを元に位置情報をリアルタイムに付与する fluent-plugin-geoip v0.0.1をリリースしました #fluentd - Y-Ken Studio](http://y-ken.hatenablog.com/entry/fluent-plugin-geoip-has-released)<br />
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = "fluent-plugin-geoip"
7
- spec.version = "1.2.0"
7
+ spec.version = "1.3.0"
8
8
  spec.authors = ["Kentaro Yoshida"]
9
9
  spec.email = ["y.ken.studio@gmail.com"]
10
10
  spec.summary = %q{Fluentd Filter plugin to add information about geographical location of IP addresses with Maxmind GeoIP databases.}
@@ -20,6 +20,7 @@ Gem::Specification.new do |spec|
20
20
  spec.add_development_dependency "rake"
21
21
  spec.add_development_dependency "appraisal"
22
22
  spec.add_development_dependency "test-unit", ">= 3.1.0"
23
+ spec.add_development_dependency "test-unit-rr"
23
24
  spec.add_development_dependency "geoip2_compat"
24
25
 
25
26
  spec.add_runtime_dependency "fluentd", [">= 0.14.8", "< 2"]
@@ -1,11 +1,37 @@
1
1
  require 'fluent/plugin/filter'
2
- require 'fluent/plugin/geoip'
2
+
3
+ require 'geoip'
4
+ require 'yajl'
5
+ unless {}.respond_to?(:dig)
6
+ begin
7
+ # backport_dig is faster than dig_rb so prefer backport_dig.
8
+ # And Fluentd v1.0.1 uses backport_dig
9
+ require 'backport_dig'
10
+ rescue LoadError
11
+ require 'dig_rb'
12
+ end
13
+ end
3
14
 
4
15
  module Fluent::Plugin
5
16
  class GeoipFilter < Fluent::Plugin::Filter
6
17
  Fluent::Plugin.register_filter('geoip', self)
7
18
 
8
- helpers :compat_parameters, :inject
19
+ BACKEND_LIBRARIES = [:geoip, :geoip2_compat, :geoip2_c]
20
+
21
+ REGEXP_PLACEHOLDER_SINGLE = /^\$\{
22
+ (?<geoip_key>-?[^\[\]]+)
23
+ \[
24
+ (?:(?<dq>")|(?<sq>'))
25
+ (?<record_key>-?(?(<dq>)[^"{}]+|[^'{}]+))
26
+ (?(<dq>)"|')
27
+ \]
28
+ \}$/x
29
+ REGEXP_PLACEHOLDER_SCAN = /['"]?(\$\{[^\}]+?\})['"]?/
30
+
31
+ GEOIP_KEYS = %w(city latitude longitude country_code3 country_code country_name dma_code area_code region)
32
+ GEOIP2_COMPAT_KEYS = %w(city country_code country_name latitude longitude postal_code region region_name)
33
+
34
+ helpers :compat_parameters, :inject, :record_accessor
9
35
 
10
36
  config_param :geoip_database, :string, default: File.expand_path('../../../data/GeoLiteCity.dat', __dir__)
11
37
  config_param :geoip2_database, :string, default: File.expand_path('../../../data/GeoLite2-City.mmdb', __dir__)
@@ -15,16 +41,69 @@ module Fluent::Plugin
15
41
 
16
42
  config_set_default :@log_level, "warn"
17
43
 
18
- config_param :backend_library, :enum, list: Fluent::GeoIP::BACKEND_LIBRARIES, default: :geoip2_c
44
+ config_param :backend_library, :enum, list: BACKEND_LIBRARIES, default: :geoip2_c
19
45
 
20
46
  def configure(conf)
21
47
  compat_parameters_convert(conf, :inject)
22
48
  super
23
- @geoip = Fluent::GeoIP.new(self, conf)
49
+
50
+ @map = {}
51
+ if @geoip_lookup_key
52
+ @geoip_lookup_keys = @geoip_lookup_key.split(/\s*,\s*/)
53
+ end
54
+
55
+ @geoip_lookup_keys.each do |key|
56
+ if key.include?(".") && !key.start_with?("$")
57
+ $log.warn("#{key} is not treated as nested attributes")
58
+ end
59
+ end
60
+ @geoip_lookup_accessors = @geoip_lookup_keys.map {|key| [key, record_accessor_create(key)] }.to_h
61
+
62
+ if conf.keys.any? {|k| k =~ /^enable_key_/ }
63
+ raise Fluent::ConfigError, "geoip: 'enable_key_*' config format is obsoleted. use <record></record> directive instead."
64
+ end
65
+
66
+ # <record></record> directive
67
+ conf.elements.select { |element| element.name == 'record' }.each { |element|
68
+ element.each_pair { |k, v|
69
+ element.has_key?(k) # to suppress unread configuration warning
70
+ v = v[1..v.size-2] if quoted_value?(v)
71
+ @map[k] = v
72
+ validate_json = Proc.new {
73
+ begin
74
+ dummy_text = Yajl::Encoder.encode('dummy_text')
75
+ Yajl::Parser.parse(v.gsub(REGEXP_PLACEHOLDER_SCAN, dummy_text))
76
+ rescue Yajl::ParseError => e
77
+ message = "geoip: failed to parse '#{v}' as json."
78
+ log.error message, error: e
79
+ raise Fluent::ConfigError, message
80
+ end
81
+ }
82
+ validate_json.call if json?(v.tr('\'"\\', ''))
83
+ }
84
+ }
85
+
86
+ @placeholder_keys = @map.values.join.scan(REGEXP_PLACEHOLDER_SCAN).map{|placeholder| placeholder[0] }.uniq
87
+ @placeholder_keys.each do |key|
88
+ m = key.match(REGEXP_PLACEHOLDER_SINGLE)
89
+ geoip_key = m[:geoip_key]
90
+ case @backend_library
91
+ when :geoip
92
+ raise Fluent::ConfigError, "#{@backend_library}: unsupported key #{geoip_key}" unless GEOIP_KEYS.include?(geoip_key)
93
+ when :geoip2_compat
94
+ raise Fluent::ConfigError, "#{@backend_library}: unsupported key #{geoip_key}" unless GEOIP2_COMPAT_KEYS.include?(geoip_key)
95
+ when :geoip2_c
96
+ # Nothing to do.
97
+ # We cannot define supported key(s) before we fetch values from GeoIP2 database
98
+ # because geoip2_c can fetch any fields in GeoIP2 database.
99
+ end
100
+ end
101
+
102
+ @geoip = load_database
24
103
  end
25
104
 
26
105
  def filter(tag, time, record)
27
- filtered_record = @geoip.add_geoip_field(record)
106
+ filtered_record = add_geoip_field(record)
28
107
  if filtered_record
29
108
  record = filtered_record
30
109
  end
@@ -35,5 +114,101 @@ module Fluent::Plugin
35
114
  def multi_workers_ready?
36
115
  true
37
116
  end
117
+
118
+ private
119
+
120
+ def add_geoip_field(record)
121
+ placeholder = create_placeholder(geolocate(get_address(record)))
122
+ return record if @skip_adding_null_record && placeholder.values.first.nil?
123
+ @map.each do |record_key, value|
124
+ if value.match(REGEXP_PLACEHOLDER_SINGLE) #|| value.match(REGEXP_PLACEHOLDER_BRACKET_SINGLE)
125
+ rewrited = placeholder[value]
126
+ elsif json?(value)
127
+ rewrited = value.gsub(REGEXP_PLACEHOLDER_SCAN) {|match|
128
+ match = match[1..match.size-2] if quoted_value?(match)
129
+ Yajl::Encoder.encode(placeholder[match])
130
+ }
131
+ rewrited = parse_json(rewrited)
132
+ else
133
+ rewrited = value.gsub(REGEXP_PLACEHOLDER_SCAN, placeholder)
134
+ end
135
+ record[record_key] = rewrited
136
+ end
137
+ record
138
+ end
139
+
140
+ def json?(text)
141
+ text.match(/^\[.+\]$/) || text.match(/^\{.+\}$/)
142
+ end
143
+
144
+ def quoted_value?(text)
145
+ # to improbe compatibility with fluentd v1-config
146
+ text.match(/(^'.+'$|^".+"$)/)
147
+ end
148
+
149
+ def parse_json(message)
150
+ begin
151
+ return Yajl::Parser.parse(message)
152
+ rescue Yajl::ParseError => e
153
+ log.info "geoip: failed to parse '#{message}' as json.", error_class: e.class, error: e.message
154
+ return nil
155
+ end
156
+ end
157
+
158
+ def get_address(record)
159
+ address = {}
160
+ @geoip_lookup_accessors.each do |field, accessor|
161
+ address[field] = accessor.call(record)
162
+ end
163
+ address
164
+ end
165
+
166
+ def geolocate(addresses)
167
+ geodata = {}
168
+ addresses.each do |field, ip|
169
+ geo = nil
170
+ if ip
171
+ geo = if @geoip.respond_to?(:look_up)
172
+ @geoip.look_up(ip)
173
+ else
174
+ @geoip.lookup(ip)
175
+ end
176
+ end
177
+ geodata[field] = geo
178
+ end
179
+ geodata
180
+ end
181
+
182
+ def create_placeholder(geodata)
183
+ placeholder = {}
184
+ @placeholder_keys.each do |placeholder_key|
185
+ position = placeholder_key.match(REGEXP_PLACEHOLDER_SINGLE)
186
+ next if position.nil? or geodata[position[:record_key]].nil?
187
+ keys = [position[:record_key]] + position[:geoip_key].split('.').map(&:to_sym)
188
+ value = geodata.dig(*keys)
189
+ value = if [:latitude, :longitude].include?(keys.last)
190
+ value || 0.0
191
+ else
192
+ value
193
+ end
194
+ placeholder[placeholder_key] = value
195
+ end
196
+ placeholder
197
+ end
198
+
199
+ def load_database
200
+ case @backend_library
201
+ when :geoip
202
+ ::GeoIP::City.new(@geoip_database, :memory, false)
203
+ when :geoip2_compat
204
+ require 'geoip2_compat'
205
+ GeoIP2Compat.new(@geoip2_database)
206
+ when :geoip2_c
207
+ require 'geoip2'
208
+ GeoIP2::Database.new(@geoip2_database)
209
+ end
210
+ rescue LoadError
211
+ raise Fluent::ConfigError, "You must install #{@backend_library} gem."
212
+ end
38
213
  end
39
214
  end