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 +4 -4
- data/README.md +90 -211
- data/fluent-plugin-geoip.gemspec +2 -1
- data/lib/fluent/plugin/filter_geoip.rb +180 -5
- data/test/helper.rb +1 -0
- data/test/plugin/test_filter_geoip.rb +137 -69
- metadata +17 -7
- data/lib/fluent/plugin/geoip.rb +0 -171
- data/lib/fluent/plugin/out_geoip.rb +0 -56
- data/test/plugin/test_out_geoip.rb +0 -1048
data/test/helper.rb
CHANGED
@@ -31,12 +31,12 @@ class GeoipFilterTest < Test::Unit::TestCase
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def setup_geoip_mock(d)
|
34
|
-
|
34
|
+
plugin = d.instance
|
35
35
|
db = Object.new
|
36
36
|
def db.lookup(ip)
|
37
37
|
{}
|
38
38
|
end
|
39
|
-
|
39
|
+
plugin.instance_variable_set(:@geoip, db)
|
40
40
|
end
|
41
41
|
|
42
42
|
sub_test_case "configure" do
|
@@ -58,11 +58,9 @@ class GeoipFilterTest < Test::Unit::TestCase
|
|
58
58
|
<record>
|
59
59
|
geoip_city ${city['host']}
|
60
60
|
</record>
|
61
|
-
tag geoip.${tag[1]}
|
62
61
|
]
|
63
62
|
d = create_driver(conf)
|
64
|
-
assert_equal(["host", "ip"],
|
65
|
-
d.instance.instance_variable_get(:@geoip).instance_variable_get(:@geoip_lookup_keys))
|
63
|
+
assert_equal(["host", "ip"], d.instance.geoip_lookup_keys)
|
66
64
|
end
|
67
65
|
|
68
66
|
test "invalid json structure w/ Ruby hash like" do
|
@@ -87,6 +85,36 @@ class GeoipFilterTest < Test::Unit::TestCase
|
|
87
85
|
}
|
88
86
|
end
|
89
87
|
|
88
|
+
test "dotted key is not treated as nested attributes" do
|
89
|
+
mock($log).warn("host.ip is not treated as nested attributes")
|
90
|
+
create_driver %[
|
91
|
+
geoip_lookup_keys host.ip
|
92
|
+
<record>
|
93
|
+
city ${city.names.en['host.ip']}
|
94
|
+
</record>
|
95
|
+
]
|
96
|
+
end
|
97
|
+
|
98
|
+
test "nested attributes bracket style" do
|
99
|
+
mock($log).warn(anything).times(0)
|
100
|
+
create_driver %[
|
101
|
+
geoip_lookup_keys $["host"]["ip"]
|
102
|
+
<record>
|
103
|
+
geoip_city ${city.names.en['$["host"]["ip"]']}
|
104
|
+
</record>
|
105
|
+
]
|
106
|
+
end
|
107
|
+
|
108
|
+
test "nested attributes dot style" do
|
109
|
+
mock($log).warn(anything).times(0)
|
110
|
+
create_driver %[
|
111
|
+
geoip_lookup_keys $.host.ip
|
112
|
+
<record>
|
113
|
+
geoip_city ${city['$.host.ip']}
|
114
|
+
</record>
|
115
|
+
]
|
116
|
+
end
|
117
|
+
|
90
118
|
data(geoip: "geoip",
|
91
119
|
geoip2_compat: "geoip2_compat")
|
92
120
|
test "unsupported key" do |backend|
|
@@ -197,21 +225,21 @@ class GeoipFilterTest < Test::Unit::TestCase
|
|
197
225
|
def test_filter_record_directive
|
198
226
|
config = %[
|
199
227
|
backend_library geoip2_c
|
200
|
-
geoip_lookup_keys from.ip
|
228
|
+
geoip_lookup_keys $.from.ip
|
201
229
|
<record>
|
202
|
-
from_city ${city.names.en['from.ip']}
|
203
|
-
from_country ${country.names.en['from.ip']}
|
204
|
-
latitude ${location.latitude['from.ip']}
|
205
|
-
longitude ${location.longitude['from.ip']}
|
206
|
-
float_concat ${location.latitude['from.ip']},${location.longitude['from.ip']}
|
207
|
-
float_array [${location.longitude['from.ip']}, ${location.latitude['from.ip']}]
|
208
|
-
float_nest { "lat" : ${location.latitude['from.ip']}, "lon" : ${location.longitude['from.ip']}}
|
209
|
-
string_concat ${city.names.en['from.ip']},${country.names.en['from.ip']}
|
210
|
-
string_array [${city.names.en['from.ip']}, ${country.names.en['from.ip']}]
|
211
|
-
string_nest { "city" : ${city.names.en['from.ip']}, "country_name" : ${country.names.en['from.ip']}}
|
230
|
+
from_city ${city.names.en['$.from.ip']}
|
231
|
+
from_country ${country.names.en['$.from.ip']}
|
232
|
+
latitude ${location.latitude['$.from.ip']}
|
233
|
+
longitude ${location.longitude['$.from.ip']}
|
234
|
+
float_concat ${location.latitude['$.from.ip']},${location.longitude['$.from.ip']}
|
235
|
+
float_array [${location.longitude['$.from.ip']}, ${location.latitude['$.from.ip']}]
|
236
|
+
float_nest { "lat" : ${location.latitude['$.from.ip']}, "lon" : ${location.longitude['$.from.ip']}}
|
237
|
+
string_concat ${city.names.en['$.from.ip']},${country.names.en['$.from.ip']}
|
238
|
+
string_array [${city.names.en['$.from.ip']}, ${country.names.en['$.from.ip']}]
|
239
|
+
string_nest { "city" : ${city.names.en['$.from.ip']}, "country_name" : ${country.names.en['$.from.ip']}}
|
212
240
|
unknown_city ${city.names.en['unknown_key']}
|
213
241
|
undefined ${city.names.en['undefined']}
|
214
|
-
broken_array1 [${location.longitude['from.ip']}, ${location.latitude['undefined']}]
|
242
|
+
broken_array1 [${location.longitude['$.from.ip']}, ${location.latitude['undefined']}]
|
215
243
|
broken_array2 [${location.longitude['undefined']}, ${location.latitude['undefined']}]
|
216
244
|
</record>
|
217
245
|
]
|
@@ -264,13 +292,13 @@ class GeoipFilterTest < Test::Unit::TestCase
|
|
264
292
|
def test_filter_record_directive_multiple_record
|
265
293
|
config = %[
|
266
294
|
backend_library geoip2_c
|
267
|
-
geoip_lookup_keys from.ip, to.ip
|
295
|
+
geoip_lookup_keys $.from.ip, $.to.ip
|
268
296
|
<record>
|
269
|
-
from_city ${city.names.en['from.ip']}
|
270
|
-
to_city ${city.names.en['to.ip']}
|
271
|
-
from_country ${country.names.en['from.ip']}
|
272
|
-
to_country ${country.names.en['to.ip']}
|
273
|
-
string_array [${country.names.en['from.ip']}, ${country.names.en['to.ip']}]
|
297
|
+
from_city ${city.names.en['$.from.ip']}
|
298
|
+
to_city ${city.names.en['$.to.ip']}
|
299
|
+
from_country ${country.names.en['$.from.ip']}
|
300
|
+
to_country ${country.names.en['$.to.ip']}
|
301
|
+
string_array [${country.names.en['$.from.ip']}, ${country.names.en['$.to.ip']}]
|
274
302
|
</record>
|
275
303
|
]
|
276
304
|
messages = [
|
@@ -417,6 +445,46 @@ class GeoipFilterTest < Test::Unit::TestCase
|
|
417
445
|
end
|
418
446
|
assert_equal(expected, filtered)
|
419
447
|
end
|
448
|
+
|
449
|
+
def test_filter_nested_attr_bracket_style_double_quote
|
450
|
+
config = %[
|
451
|
+
backend_library geoip2_c
|
452
|
+
geoip_lookup_keys $["host"]["ip"]
|
453
|
+
<record>
|
454
|
+
geoip_city ${city.names.en['$["host"]["ip"]']}
|
455
|
+
</record>
|
456
|
+
]
|
457
|
+
messages = [
|
458
|
+
{'host' => {'ip' => '66.102.3.80'}, 'message' => 'valid ip'},
|
459
|
+
{'message' => 'missing field'}
|
460
|
+
]
|
461
|
+
expected = [
|
462
|
+
{'host' => {'ip' => '66.102.3.80'}, 'message' => 'valid ip', 'geoip_city' => 'Mountain View'},
|
463
|
+
{'message' => 'missing field', 'geoip_city' => nil}
|
464
|
+
]
|
465
|
+
filtered = filter(config, messages)
|
466
|
+
assert_equal(expected, filtered)
|
467
|
+
end
|
468
|
+
|
469
|
+
def test_filter_nested_attr_bracket_style_single_quote
|
470
|
+
config = %[
|
471
|
+
backend_library geoip2_c
|
472
|
+
geoip_lookup_keys $['host']['ip']
|
473
|
+
<record>
|
474
|
+
geoip_city ${city.names.en["$['host']['ip']"]}
|
475
|
+
</record>
|
476
|
+
]
|
477
|
+
messages = [
|
478
|
+
{'host' => {'ip' => '66.102.3.80'}, 'message' => 'valid ip'},
|
479
|
+
{'message' => 'missing field'}
|
480
|
+
]
|
481
|
+
expected = [
|
482
|
+
{'host' => {'ip' => '66.102.3.80'}, 'message' => 'valid ip', 'geoip_city' => 'Mountain View'},
|
483
|
+
{'message' => 'missing field', 'geoip_city' => nil}
|
484
|
+
]
|
485
|
+
filtered = filter(config, messages)
|
486
|
+
assert_equal(expected, filtered)
|
487
|
+
end
|
420
488
|
end
|
421
489
|
|
422
490
|
sub_test_case "geoip2_compat" do
|
@@ -492,21 +560,21 @@ class GeoipFilterTest < Test::Unit::TestCase
|
|
492
560
|
def test_filter_record_directive
|
493
561
|
config = %[
|
494
562
|
backend_library geoip2_compat
|
495
|
-
geoip_lookup_keys from.ip
|
563
|
+
geoip_lookup_keys $.from.ip
|
496
564
|
<record>
|
497
|
-
from_city ${city['from.ip']}
|
498
|
-
from_country ${country_name['from.ip']}
|
499
|
-
latitude ${latitude['from.ip']}
|
500
|
-
longitude ${longitude['from.ip']}
|
501
|
-
float_concat ${latitude['from.ip']},${longitude['from.ip']}
|
502
|
-
float_array [${longitude['from.ip']}, ${latitude['from.ip']}]
|
503
|
-
float_nest { "lat" : ${latitude['from.ip']}, "lon" : ${longitude['from.ip']}}
|
504
|
-
string_concat ${city['from.ip']},${country_name['from.ip']}
|
505
|
-
string_array [${city['from.ip']}, ${country_name['from.ip']}]
|
506
|
-
string_nest { "city" : ${city['from.ip']}, "country_name" : ${country_name['from.ip']}}
|
565
|
+
from_city ${city['$.from.ip']}
|
566
|
+
from_country ${country_name['$.from.ip']}
|
567
|
+
latitude ${latitude['$.from.ip']}
|
568
|
+
longitude ${longitude['$.from.ip']}
|
569
|
+
float_concat ${latitude['$.from.ip']},${longitude['$.from.ip']}
|
570
|
+
float_array [${longitude['$.from.ip']}, ${latitude['$.from.ip']}]
|
571
|
+
float_nest { "lat" : ${latitude['$.from.ip']}, "lon" : ${longitude['$.from.ip']}}
|
572
|
+
string_concat ${city['$.from.ip']},${country_name['$.from.ip']}
|
573
|
+
string_array [${city['$.from.ip']}, ${country_name['$.from.ip']}]
|
574
|
+
string_nest { "city" : ${city['$.from.ip']}, "country_name" : ${country_name['$.from.ip']}}
|
507
575
|
unknown_city ${city['unknown_key']}
|
508
576
|
undefined ${city['undefined']}
|
509
|
-
broken_array1 [${longitude['from.ip']}, ${latitude['undefined']}]
|
577
|
+
broken_array1 [${longitude['$.from.ip']}, ${latitude['undefined']}]
|
510
578
|
broken_array2 [${longitude['undefined']}, ${latitude['undefined']}]
|
511
579
|
</record>
|
512
580
|
]
|
@@ -559,13 +627,13 @@ class GeoipFilterTest < Test::Unit::TestCase
|
|
559
627
|
def test_filter_record_directive_multiple_record
|
560
628
|
config = %[
|
561
629
|
backend_library geoip2_compat
|
562
|
-
geoip_lookup_keys from.ip, to.ip
|
630
|
+
geoip_lookup_keys $.from.ip, $.to.ip
|
563
631
|
<record>
|
564
|
-
from_city ${city['from.ip']}
|
565
|
-
to_city ${city['to.ip']}
|
566
|
-
from_country ${country_name['from.ip']}
|
567
|
-
to_country ${country_name['to.ip']}
|
568
|
-
string_array [${country_name['from.ip']}, ${country_name['to.ip']}]
|
632
|
+
from_city ${city['$.from.ip']}
|
633
|
+
to_city ${city['$.to.ip']}
|
634
|
+
from_country ${country_name['$.from.ip']}
|
635
|
+
to_country ${country_name['$.to.ip']}
|
636
|
+
string_array [${country_name['$.from.ip']}, ${country_name['$.to.ip']}]
|
569
637
|
</record>
|
570
638
|
]
|
571
639
|
messages = [
|
@@ -758,9 +826,9 @@ class GeoipFilterTest < Test::Unit::TestCase
|
|
758
826
|
def test_filter_nested_attr
|
759
827
|
config = %[
|
760
828
|
backend_library geoip
|
761
|
-
geoip_lookup_keys host.ip
|
829
|
+
geoip_lookup_keys $.host.ip
|
762
830
|
<record>
|
763
|
-
geoip_city ${city['host.ip']}
|
831
|
+
geoip_city ${city['$.host.ip']}
|
764
832
|
</record>
|
765
833
|
]
|
766
834
|
messages = [
|
@@ -827,10 +895,10 @@ class GeoipFilterTest < Test::Unit::TestCase
|
|
827
895
|
def test_filter_multiple_key
|
828
896
|
config = %[
|
829
897
|
backend_library geoip
|
830
|
-
geoip_lookup_keys from.ip, to.ip
|
898
|
+
geoip_lookup_keys $.from.ip, $.to.ip
|
831
899
|
<record>
|
832
|
-
from_city ${city['from.ip']}
|
833
|
-
to_city ${city['to.ip']}
|
900
|
+
from_city ${city['$.from.ip']}
|
901
|
+
to_city ${city['$.to.ip']}
|
834
902
|
</record>
|
835
903
|
]
|
836
904
|
messages = [
|
@@ -849,12 +917,12 @@ class GeoipFilterTest < Test::Unit::TestCase
|
|
849
917
|
def test_filter_multiple_key_multiple_record
|
850
918
|
config = %[
|
851
919
|
backend_library geoip
|
852
|
-
geoip_lookup_keys from.ip, to.ip
|
920
|
+
geoip_lookup_keys $.from.ip, $.to.ip
|
853
921
|
<record>
|
854
|
-
from_city ${city['from.ip']}
|
855
|
-
from_country ${country_name['from.ip']}
|
856
|
-
to_city ${city['to.ip']}
|
857
|
-
to_country ${country_name['to.ip']}
|
922
|
+
from_city ${city['$.from.ip']}
|
923
|
+
from_country ${country_name['$.from.ip']}
|
924
|
+
to_city ${city['$.to.ip']}
|
925
|
+
to_country ${country_name['$.to.ip']}
|
858
926
|
</record>
|
859
927
|
]
|
860
928
|
messages = [
|
@@ -893,21 +961,21 @@ class GeoipFilterTest < Test::Unit::TestCase
|
|
893
961
|
def test_filter_record_directive
|
894
962
|
config = %[
|
895
963
|
backend_library geoip
|
896
|
-
geoip_lookup_keys from.ip
|
964
|
+
geoip_lookup_keys $.from.ip
|
897
965
|
<record>
|
898
|
-
from_city ${city['from.ip']}
|
899
|
-
from_country ${country_name['from.ip']}
|
900
|
-
latitude ${latitude['from.ip']}
|
901
|
-
longitude ${longitude['from.ip']}
|
902
|
-
float_concat ${latitude['from.ip']},${longitude['from.ip']}
|
903
|
-
float_array [${longitude['from.ip']}, ${latitude['from.ip']}]
|
904
|
-
float_nest { "lat" : ${latitude['from.ip']}, "lon" : ${longitude['from.ip']}}
|
905
|
-
string_concat ${city['from.ip']},${country_name['from.ip']}
|
906
|
-
string_array [${city['from.ip']}, ${country_name['from.ip']}]
|
907
|
-
string_nest { "city" : ${city['from.ip']}, "country_name" : ${country_name['from.ip']}}
|
966
|
+
from_city ${city['$.from.ip']}
|
967
|
+
from_country ${country_name['$.from.ip']}
|
968
|
+
latitude ${latitude['$.from.ip']}
|
969
|
+
longitude ${longitude['$.from.ip']}
|
970
|
+
float_concat ${latitude['$.from.ip']},${longitude['$.from.ip']}
|
971
|
+
float_array [${longitude['$.from.ip']}, ${latitude['$.from.ip']}]
|
972
|
+
float_nest { "lat" : ${latitude['$.from.ip']}, "lon" : ${longitude['$.from.ip']}}
|
973
|
+
string_concat ${city['$.from.ip']},${country_name['$.from.ip']}
|
974
|
+
string_array [${city['$.from.ip']}, ${country_name['$.from.ip']}]
|
975
|
+
string_nest { "city" : ${city['$.from.ip']}, "country_name" : ${country_name['$.from.ip']}}
|
908
976
|
unknown_city ${city['unknown_key']}
|
909
977
|
undefined ${city['undefined']}
|
910
|
-
broken_array1 [${longitude['from.ip']}, ${latitude['undefined']}]
|
978
|
+
broken_array1 [${longitude['$.from.ip']}, ${latitude['undefined']}]
|
911
979
|
broken_array2 [${longitude['undefined']}, ${latitude['undefined']}]
|
912
980
|
</record>
|
913
981
|
]
|
@@ -960,13 +1028,13 @@ class GeoipFilterTest < Test::Unit::TestCase
|
|
960
1028
|
def test_filter_record_directive_multiple_record
|
961
1029
|
config = %[
|
962
1030
|
backend_library geoip
|
963
|
-
geoip_lookup_keys from.ip, to.ip
|
1031
|
+
geoip_lookup_keys $.from.ip, $.to.ip
|
964
1032
|
<record>
|
965
|
-
from_city ${city['from.ip']}
|
966
|
-
to_city ${city['to.ip']}
|
967
|
-
from_country ${country_name['from.ip']}
|
968
|
-
to_country ${country_name['to.ip']}
|
969
|
-
string_array [${country_name['from.ip']}, ${country_name['to.ip']}]
|
1033
|
+
from_city ${city['$.from.ip']}
|
1034
|
+
to_city ${city['$.to.ip']}
|
1035
|
+
from_country ${country_name['$.from.ip']}
|
1036
|
+
to_country ${country_name['$.to.ip']}
|
1037
|
+
string_array [${country_name['$.from.ip']}, ${country_name['$.to.ip']}]
|
970
1038
|
</record>
|
971
1039
|
]
|
972
1040
|
messages = [
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluent-plugin-geoip
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kentaro Yoshida
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-11-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: 3.1.0
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: test-unit-rr
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: geoip2_compat
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -172,11 +186,8 @@ files:
|
|
172
186
|
- gemfiles/fluentd_v1.0_with_backport_dig.gemfile
|
173
187
|
- gemfiles/fluentd_v1.0_without_backport_dig.gemfile
|
174
188
|
- lib/fluent/plugin/filter_geoip.rb
|
175
|
-
- lib/fluent/plugin/geoip.rb
|
176
|
-
- lib/fluent/plugin/out_geoip.rb
|
177
189
|
- test/helper.rb
|
178
190
|
- test/plugin/test_filter_geoip.rb
|
179
|
-
- test/plugin/test_out_geoip.rb
|
180
191
|
- utils/dump.rb
|
181
192
|
homepage: https://github.com/y-ken/fluent-plugin-geoip
|
182
193
|
licenses:
|
@@ -198,7 +209,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
198
209
|
version: '0'
|
199
210
|
requirements: []
|
200
211
|
rubyforge_project:
|
201
|
-
rubygems_version: 2.7.
|
212
|
+
rubygems_version: 2.7.6
|
202
213
|
signing_key:
|
203
214
|
specification_version: 4
|
204
215
|
summary: Fluentd Filter plugin to add information about geographical location of IP
|
@@ -206,4 +217,3 @@ summary: Fluentd Filter plugin to add information about geographical location of
|
|
206
217
|
test_files:
|
207
218
|
- test/helper.rb
|
208
219
|
- test/plugin/test_filter_geoip.rb
|
209
|
-
- test/plugin/test_out_geoip.rb
|
data/lib/fluent/plugin/geoip.rb
DELETED
@@ -1,171 +0,0 @@
|
|
1
|
-
require 'geoip'
|
2
|
-
require 'yajl'
|
3
|
-
unless {}.respond_to?(:dig)
|
4
|
-
begin
|
5
|
-
# backport_dig is faster than dig_rb so prefer backport_dig.
|
6
|
-
# And Fluentd v1.0.1 uses backport_dig
|
7
|
-
require 'backport_dig'
|
8
|
-
rescue LoadError
|
9
|
-
require 'dig_rb'
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
module Fluent
|
14
|
-
class GeoIP
|
15
|
-
BACKEND_LIBRARIES = [:geoip, :geoip2_compat, :geoip2_c]
|
16
|
-
|
17
|
-
REGEXP_PLACEHOLDER_SINGLE = /^\$\{(?<geoip_key>-?[^\[]+)\[['"](?<record_key>-?[^'"]+)['"]\]\}$/
|
18
|
-
REGEXP_PLACEHOLDER_SCAN = /['"]?(\$\{[^\}]+?\})['"]?/
|
19
|
-
|
20
|
-
GEOIP_KEYS = %w(city latitude longitude country_code3 country_code country_name dma_code area_code region)
|
21
|
-
GEOIP2_COMPAT_KEYS = %w(city country_code country_name latitude longitude postal_code region region_name)
|
22
|
-
|
23
|
-
attr_reader :log
|
24
|
-
|
25
|
-
def initialize(plugin, conf)
|
26
|
-
@map = {}
|
27
|
-
@geoip_lookup_keys = plugin.geoip_lookup_keys
|
28
|
-
if plugin.geoip_lookup_key
|
29
|
-
@geoip_lookup_keys = plugin.geoip_lookup_key.split(/\s*,\s*/)
|
30
|
-
end
|
31
|
-
@skip_adding_null_record = plugin.skip_adding_null_record
|
32
|
-
@log = plugin.log
|
33
|
-
|
34
|
-
if conf.keys.any? {|k| k =~ /^enable_key_/ }
|
35
|
-
raise Fluent::ConfigError, "geoip: 'enable_key_*' config format is obsoleted. use <record></record> directive instead."
|
36
|
-
end
|
37
|
-
|
38
|
-
# <record></record> directive
|
39
|
-
conf.elements.select { |element| element.name == 'record' }.each { |element|
|
40
|
-
element.each_pair { |k, v|
|
41
|
-
element.has_key?(k) # to suppress unread configuration warning
|
42
|
-
v = v[1..v.size-2] if quoted_value?(v)
|
43
|
-
@map[k] = v
|
44
|
-
validate_json = Proc.new {
|
45
|
-
begin
|
46
|
-
dummy_text = Yajl::Encoder.encode('dummy_text')
|
47
|
-
Yajl::Parser.parse(v.gsub(REGEXP_PLACEHOLDER_SCAN, dummy_text))
|
48
|
-
rescue Yajl::ParseError => e
|
49
|
-
message = "geoip: failed to parse '#{v}' as json."
|
50
|
-
log.error message, error: e
|
51
|
-
raise Fluent::ConfigError, message
|
52
|
-
end
|
53
|
-
}
|
54
|
-
validate_json.call if json?(v.tr('\'"\\', ''))
|
55
|
-
}
|
56
|
-
}
|
57
|
-
@placeholder_keys = @map.values.join.scan(REGEXP_PLACEHOLDER_SCAN).map{ |placeholder| placeholder[0] }.uniq
|
58
|
-
@placeholder_keys.each do |key|
|
59
|
-
geoip_key = key.match(REGEXP_PLACEHOLDER_SINGLE)[:geoip_key]
|
60
|
-
case plugin.backend_library
|
61
|
-
when :geoip
|
62
|
-
raise Fluent::ConfigError, "#{plugin.backend_library}: unsupported key #{geoip_key}" unless GEOIP_KEYS.include?(geoip_key)
|
63
|
-
when :geoip2_compat
|
64
|
-
raise Fluent::ConfigError, "#{plugin.backend_library}: unsupported key #{geoip_key}" unless GEOIP2_COMPAT_KEYS.include?(geoip_key)
|
65
|
-
when :geoip2_c
|
66
|
-
# Nothing to do.
|
67
|
-
# We cannot define supported key(s) before we fetch values from GeoIP2 database
|
68
|
-
# because geoip2_c can fetch any fields in GeoIP2 database.
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
@geoip = load_database(plugin)
|
73
|
-
end
|
74
|
-
|
75
|
-
def add_geoip_field(record)
|
76
|
-
placeholder = create_placeholder(geolocate(get_address(record)))
|
77
|
-
return record if @skip_adding_null_record && placeholder.values.first.nil?
|
78
|
-
@map.each do |record_key, value|
|
79
|
-
if value.match(REGEXP_PLACEHOLDER_SINGLE)
|
80
|
-
rewrited = placeholder[value]
|
81
|
-
elsif json?(value)
|
82
|
-
rewrited = value.gsub(REGEXP_PLACEHOLDER_SCAN) {|match|
|
83
|
-
match = match[1..match.size-2] if quoted_value?(match)
|
84
|
-
Yajl::Encoder.encode(placeholder[match])
|
85
|
-
}
|
86
|
-
rewrited = parse_json(rewrited)
|
87
|
-
else
|
88
|
-
rewrited = value.gsub(REGEXP_PLACEHOLDER_SCAN, placeholder)
|
89
|
-
end
|
90
|
-
record[record_key] = rewrited
|
91
|
-
end
|
92
|
-
return record
|
93
|
-
end
|
94
|
-
|
95
|
-
private
|
96
|
-
|
97
|
-
def json?(text)
|
98
|
-
text.match(/^\[.+\]$/) || text.match(/^\{.+\}$/)
|
99
|
-
end
|
100
|
-
|
101
|
-
def quoted_value?(text)
|
102
|
-
# to improbe compatibility with fluentd v1-config
|
103
|
-
text.match(/(^'.+'$|^".+"$)/)
|
104
|
-
end
|
105
|
-
|
106
|
-
def parse_json(message)
|
107
|
-
begin
|
108
|
-
return Yajl::Parser.parse(message)
|
109
|
-
rescue Yajl::ParseError => e
|
110
|
-
log.info "geoip: failed to parse '#{message}' as json.", error_class: e.class, error: e.message
|
111
|
-
return nil
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
def get_address(record)
|
116
|
-
address = {}
|
117
|
-
@geoip_lookup_keys.each do |field|
|
118
|
-
address[field] = record[field] || record.dig(*field.split('.'))
|
119
|
-
end
|
120
|
-
address
|
121
|
-
end
|
122
|
-
|
123
|
-
def geolocate(addresses)
|
124
|
-
geodata = {}
|
125
|
-
addresses.each do |field, ip|
|
126
|
-
geo = nil
|
127
|
-
if ip
|
128
|
-
geo = if @geoip.respond_to?(:look_up)
|
129
|
-
@geoip.look_up(ip)
|
130
|
-
else
|
131
|
-
@geoip.lookup(ip)
|
132
|
-
end
|
133
|
-
end
|
134
|
-
geodata[field] = geo
|
135
|
-
end
|
136
|
-
geodata
|
137
|
-
end
|
138
|
-
|
139
|
-
def create_placeholder(geodata)
|
140
|
-
placeholder = {}
|
141
|
-
@placeholder_keys.each do |placeholder_key|
|
142
|
-
position = placeholder_key.match(REGEXP_PLACEHOLDER_SINGLE)
|
143
|
-
next if position.nil? or geodata[position[:record_key]].nil?
|
144
|
-
keys = [position[:record_key]] + position[:geoip_key].split('.').map(&:to_sym)
|
145
|
-
value = geodata.dig(*keys)
|
146
|
-
value = if [:latitude, :longitude].include?(keys.last)
|
147
|
-
value || 0.0
|
148
|
-
else
|
149
|
-
value
|
150
|
-
end
|
151
|
-
placeholder[placeholder_key] = value
|
152
|
-
end
|
153
|
-
placeholder
|
154
|
-
end
|
155
|
-
|
156
|
-
def load_database(plugin)
|
157
|
-
case plugin.backend_library
|
158
|
-
when :geoip
|
159
|
-
::GeoIP::City.new(plugin.geoip_database, :memory, false)
|
160
|
-
when :geoip2_compat
|
161
|
-
require 'geoip2_compat'
|
162
|
-
GeoIP2Compat.new(plugin.geoip2_database)
|
163
|
-
when :geoip2_c
|
164
|
-
require 'geoip2'
|
165
|
-
GeoIP2::Database.new(plugin.geoip2_database)
|
166
|
-
end
|
167
|
-
rescue LoadError
|
168
|
-
raise Fluent::ConfigError, "You must install #{plugin.backend_library} gem."
|
169
|
-
end
|
170
|
-
end
|
171
|
-
end
|