fluent-plugin-geoip 1.2.0 → 1.3.0

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: 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