fluent-plugin-filter-geoip2 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 8ac882bd000f48b5d8a4ec195553746e4c98017402222bdd685c64cbf8554ecc
4
+ data.tar.gz: c82f952ba08b6a1892c100bb5daf097354eb065b44c7a8bc693f3a7a420ab627
5
+ SHA512:
6
+ metadata.gz: b6723cf6facb64af533f39e878b9b91bcc4b6aeeea6d892b33fd0657ec5a7b344e79d20774f53e18790a1ce7bc57386078ea32e7287adeac5014e99f6b1379df
7
+ data.tar.gz: 36424fe02a0484646bfd42d07e8807c41d2f989f694f6eb4e4d9291837606a3b5e750407a912f990b2f05aa231ac23a4be54b868a1ddb2db7fd7c516764372b6
data/.gitignore ADDED
@@ -0,0 +1,43 @@
1
+ *.gem
2
+ *.rbc
3
+ *.mmdb
4
+ /test*.rb
5
+ /.config
6
+ /coverage/
7
+ /InstalledFiles
8
+ /pkg/
9
+ /spec/reports/
10
+ /test/tmp/
11
+ /test/version_tmp/
12
+ /tmp/
13
+
14
+ ## Specific to RubyMotion:
15
+ .dat*
16
+ .repl_history
17
+ build/
18
+
19
+ ## Documentation cache and generated files:
20
+ /.yardoc/
21
+ /_yardoc/
22
+ /doc/
23
+ /rdoc/
24
+
25
+ ## Environment normalisation:
26
+ /.bundle/
27
+ /vendor/bundle
28
+ /lib/bundler/man/
29
+
30
+ # for a library or gem, you might want to ignore these files since the code is
31
+ # intended to run in multiple environments; otherwise, check them in:
32
+ # Gemfile.lock
33
+ # .ruby-version
34
+ # .ruby-gemset
35
+
36
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
37
+ .rvmrc
38
+
39
+ Gemfile.lock
40
+ geoip
41
+
42
+ # RubyMine
43
+ .idea/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in fluent-plugin-out_solr.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "{}"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright 2017 Tokyo Home Security Operation Center
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,327 @@
1
+ # Fluent::Plugin::GeoIP2Filter
2
+
3
+ This is a [Fluentd](http://fluentd.org/) filter plugin for adding [GeoIP data](http://dev.maxmind.com/geoip/geoip2/geolite2/) to record. Supports the new Maxmind v2 database formats.
4
+
5
+ ## Installation
6
+
7
+ Install it yourself as:
8
+
9
+ ```
10
+ $ gem install fluent-plugin-filter-geoip2
11
+ ```
12
+
13
+ ## How to build
14
+
15
+ ```
16
+ $ gem install bundler
17
+ $ bundle install
18
+ $ rake test
19
+ $ rake build
20
+ $ rake install
21
+ ```
22
+
23
+ ## Config parameters
24
+
25
+ ### enable_auto_download
26
+
27
+ If true, enable to download GeoIP2 database autometically (default: true).
28
+
29
+ ```
30
+ enable_auto_download true
31
+ ```
32
+
33
+ ### md5_url
34
+
35
+ GeoIP2 MD5 checksum URL (default: http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.tar.gz.md5)
36
+
37
+ ```
38
+ md5_url http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.tar.gz.md5
39
+ ```
40
+
41
+ ### download_url
42
+
43
+ GeoIP2 database download URL (default: http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.tar.gz).
44
+
45
+ ```
46
+ download_url http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.tar.gz
47
+ ```
48
+
49
+ ### md5_path
50
+
51
+ GeoIP2 MD5 checksum path. (default: ./geoip/database/GeoLite2-City.md5)
52
+
53
+ ```
54
+ md5_path ./geoip/database/GeoLite2-City.md5
55
+ ```
56
+
57
+ ### database_path
58
+
59
+ GeoIP2 database path. (default: ./geoip/database/GeoLite2-City.md5)
60
+
61
+ ```
62
+ database_path ./geoip/database/GeoLite2-City.mmdb
63
+ ```
64
+
65
+ ### md5_asn_url
66
+
67
+ GeoIP2 MD5 checksum URL (default: http://geolite.maxmind.com/download/geoip/database/GeoLite2-ASN.tar.gz.md5)
68
+
69
+ ```
70
+ md5_asn_url http://geolite.maxmind.com/download/geoip/database/GeoLite2-ASN.tar.gz.md5
71
+ ```
72
+
73
+ ### download_asn_url
74
+
75
+ GeoIP2 database download URL (default: http://geolite.maxmind.com/download/geoip/database/GeoLite2-ASN.tar.gz).
76
+
77
+ ```
78
+ download_asn_url http://geolite.maxmind.com/download/geoip/database/GeoLite2-ASN.tar.gz
79
+ ```
80
+
81
+ ### md5_asn_path
82
+
83
+ GeoIP2 MD5 checksum path. (default: ./geoip/database/GeoLite2-ASN.md5)
84
+
85
+ ```
86
+ md5_asn_path ./geoip/database/GeoLite2-ASN.md5
87
+ ```
88
+
89
+ ### database_asn_path
90
+
91
+ GeoIP2 database path. (default: ./geoip/database/GeoLite2-ASN.mmdb)
92
+
93
+ ```
94
+ database_asn_path ./geoip/database/GeoLite2-ASN.mmdb
95
+ ```
96
+
97
+ ### lookup_field
98
+
99
+ Specify the field name that IP address is stored (default: ip).
100
+
101
+ ```
102
+ lookup_field host
103
+ ```
104
+
105
+ ### output_field
106
+
107
+ Specify the field name that store the result (default: geoip).
108
+
109
+ ```
110
+ output_field geoip
111
+ ```
112
+
113
+ ### field_delimiter
114
+
115
+ Specify the field delimiter (default .).
116
+
117
+ ```
118
+ field_delimiter .
119
+ ```
120
+
121
+ ### flatten
122
+
123
+ If true, to flatten the result using field_delimiter (default: false).
124
+
125
+ ```
126
+ flatten false
127
+ ```
128
+
129
+ ### locale
130
+
131
+ Get the data for the specified locale (default: en).
132
+
133
+ ```
134
+ locale en
135
+ ```
136
+
137
+ ### continent
138
+
139
+ If true, to get continent information (default: true).
140
+
141
+ ```
142
+ continent true
143
+ ```
144
+
145
+ ### country
146
+
147
+ If true, to get country information (default: true).
148
+
149
+ ```
150
+ country true
151
+ ```
152
+
153
+ ### city
154
+
155
+ If true, to get city information (default: true).
156
+
157
+ ```
158
+ city true
159
+ ```
160
+
161
+ ### location
162
+
163
+ If true, to get location information (default: true).
164
+
165
+ ```
166
+ location true
167
+ ```
168
+
169
+ ### postal
170
+
171
+ If true, to get postal information (default: fasle).
172
+
173
+ ```
174
+ postal false
175
+ ```
176
+
177
+ ### registered_country
178
+
179
+ If true, to get registered country information (default: false).
180
+
181
+ ```
182
+ registered_country false
183
+ ```
184
+
185
+ ### represented_country
186
+
187
+ If true, to get represented country information (default: false).
188
+
189
+ ```
190
+ represented_country false
191
+ ```
192
+
193
+ ### subdivisions
194
+
195
+ If true, to get subdivisions information (default: false).
196
+
197
+ ```
198
+ subdivisions false
199
+ ```
200
+
201
+ ### traits
202
+
203
+ If true, to get traits information (default: false).
204
+
205
+ ```
206
+ traits false
207
+ ```
208
+
209
+ ### connection_type
210
+
211
+ If true, to get connection type information (default: false).
212
+
213
+ ```
214
+ connection_type false
215
+ ```
216
+
217
+ ### Autonomous System
218
+
219
+ Autonomous System (default: true).
220
+
221
+ ```
222
+ autonomous_system true
223
+ ```
224
+
225
+
226
+ ## Plugin setup examples
227
+
228
+ ```
229
+ <filter tail.log>
230
+ @type geoip2
231
+
232
+ enable_auto_download true
233
+
234
+ lookup_field clientip
235
+ output_field geoip
236
+ field_delimiter .
237
+ flatten false
238
+
239
+ locale en
240
+ </filter>
241
+ ```
242
+
243
+ Assuming following inputs are coming:
244
+
245
+ ```javascript
246
+ {
247
+ "clientip": "200.114.49.218"
248
+ }
249
+ ```
250
+
251
+ then output bocomes as belows:
252
+
253
+ ```javascript
254
+ {
255
+ "ufw_ips": "106.154.25.44",
256
+ "geoip": {
257
+ "continent": {
258
+ "code": "AS",
259
+ "geoname_id": 6255147,
260
+ "name": "Asia"
261
+ },
262
+ "country": {
263
+ "geoname_id": 1861060,
264
+ "iso_code": "JP",
265
+ "name": "Japan"
266
+ },
267
+ "location": {
268
+ "latitude": 35.69,
269
+ "longitude": 139.69,
270
+ "time_zone": "Asia/Tokyo"
271
+ },
272
+ "autonomous_system": {
273
+ "number": 2516,
274
+ "organization": "KDDI CORPORATION"
275
+ }
276
+ }
277
+ }
278
+ ```
279
+
280
+
281
+ ## Example command
282
+
283
+ Start fluentd using example fluent.conf.
284
+
285
+ ```
286
+ $ fluentd -c ~/github/fluent-plugin-filter-geoip/fluent.conf
287
+ 2017-03-13 15:11:31 +0900 [info]: reading config file path="/Users/mosuka/github/fluent-plugin-filter-geoip/fluent.conf"
288
+ 2017-03-13 15:11:31 +0900 [info]: starting fluentd-0.12.33
289
+ 2017-03-13 15:11:31 +0900 [info]: gem 'fluent-plugin-filter-geoip' version '0.0.1'
290
+ 2017-03-13 15:11:31 +0900 [info]: gem 'fluent-plugin-grok-parser' version '1.0.0'
291
+ 2017-03-13 15:11:31 +0900 [info]: gem 'fluent-plugin-output-solr' version '0.4.0'
292
+ 2017-03-13 15:11:31 +0900 [info]: gem 'fluent-plugin-ua-parser' version '1.1.0'
293
+ 2017-03-13 15:11:31 +0900 [info]: gem 'fluentd' version '0.12.33'
294
+ 2017-03-13 15:11:31 +0900 [info]: gem 'fluentd' version '0.12.32'
295
+ 2017-03-13 15:11:31 +0900 [info]: adding filter pattern="messages" type="geoip"
296
+ 2017-03-13 15:11:31 +0900 [info]: Current MD5: cc1f9a6f7def282bc33cb477f3379d9f
297
+ 2017-03-13 15:11:31 +0900 [info]: Fetched MD5: cc1f9a6f7def282bc33cb477f3379d9f
298
+ 2017-03-13 15:11:32 +0900 [info]: adding match pattern="messages" type="stdout"
299
+ 2017-03-13 15:11:32 +0900 [info]: adding source type="forward"
300
+ 2017-03-13 15:11:32 +0900 [info]: using configuration file: <ROOT>
301
+ <source>
302
+ @type forward
303
+ port 24224
304
+ </source>
305
+ <filter messages>
306
+ @type geoip
307
+ enable_auto_download true
308
+ lookup_field clientip
309
+ output_field geoip
310
+ field_delimiter .
311
+ flatten false
312
+ locale en
313
+ </filter>
314
+ <match messages>
315
+ type stdout
316
+ </match>
317
+ </ROOT>
318
+ 2017-03-13 15:11:32 +0900 [info]: listening fluent socket on 0.0.0.0:24224
319
+ ```
320
+
321
+ ## Development
322
+
323
+ After checking out the repo, run `bundle install` to install dependencies. Then, run `rake test` to run the tests.
324
+
325
+ ## Contributing
326
+
327
+ Bug reports and pull requests are welcome on GitHub at https://github.com/tokyohomesoc/fluent-plugin-filter-geoip2.
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |test|
5
+ test.libs << 'lib' << 'test'
6
+ test.pattern = 'test/**/test_*.rb'
7
+ test.verbose = true
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "fluent-plugin-filter-geoip2"
7
+ spec.version = "0.1.4"
8
+ spec.authors = ["imcotop SOC"]
9
+ spec.email = ["imcotop@icloud.com"]
10
+
11
+ spec.summary = "Fluent filter plugin for adding GeoIP data to record."
12
+ spec.description = "Fluent filter plugin for adding GeoIP data to record. Supports the new Maxmind v2 database formats."
13
+ spec.homepage = "https://github.com/OlehPalanskyi/fluent-plugin-filter-geoip2"
14
+
15
+ spec.license = "Apache-2.0"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_runtime_dependency 'fluentd', '~> 0.12.32'
23
+ spec.add_runtime_dependency 'maxminddb', '~> 0.1.11'
24
+
25
+ spec.add_development_dependency 'bundler', '~> 1.14.6'
26
+ spec.add_development_dependency 'rake', '~> 11.1.2'
27
+ spec.add_development_dependency 'test-unit', '~> 3.1.5'
28
+ spec.add_development_dependency 'minitest', '~> 5.8.3'
29
+ end
data/fluent.conf ADDED
@@ -0,0 +1,36 @@
1
+ <source>
2
+ @type forward
3
+ port 24224
4
+ </source>
5
+
6
+ <filter messages>
7
+ @type geoip2
8
+
9
+ enable_auto_download true
10
+ md5_url http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.md5
11
+ download_url http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.mmdb.gz
12
+ md5_path ./geoip/database/GeoLite2-City.md5
13
+ database_path ./geoip/database/GeoLite2-City.mmdb
14
+
15
+ lookup_field clientip
16
+ output_field geoip
17
+ field_delimiter .
18
+ flatten false
19
+
20
+ locale en
21
+
22
+ continent true
23
+ country true
24
+ city true
25
+ location true
26
+ postal true
27
+ registered_country true
28
+ represented_country true
29
+ subdivisions true
30
+ traits true
31
+ connection_type true
32
+ </filter>
33
+
34
+ <match messages>
35
+ type stdout
36
+ </match>
@@ -0,0 +1,520 @@
1
+ require 'maxminddb'
2
+ require 'json'
3
+ require 'fileutils'
4
+ require 'open-uri'
5
+ require 'zlib'
6
+ require 'fileutils'
7
+
8
+ module Fluent
9
+ class GeoIP2Filter < Filter
10
+ Fluent::Plugin.register_filter('geoip2', self)
11
+
12
+ DEFAULT_ENABLE_DOWNLOAD = true
13
+
14
+ DEFAULT_MD5_CITY_URL = 'http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.tar.gz.md5'
15
+ DEFAULT_DOWNLOAD_CITY_URL = 'http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.tar.gz'
16
+ DEFAULT_MD5_CITY_PATH = './geoip/database/GeoLite2-City.md5'
17
+ DEFAULT_DATABASE_CITY_PATH = './geoip/database/GeoLite2-City.mmdb'
18
+
19
+ DEFAULT_MD5_ASN_URL = 'http://geolite.maxmind.com/download/geoip/database/GeoLite2-ASN.tar.gz.md5'
20
+ DEFAULT_DOWNLOAD_ASN_URL = 'http://geolite.maxmind.com/download/geoip/database/GeoLite2-ASN.tar.gz'
21
+ DEFAULT_MD5_ASN_PATH = './geoip/database/GeoLite2-ASN.md5'
22
+ DEFAULT_DATABASE_ASN_PATH = './geoip/database/GeoLite2-ASN.mmdb'
23
+
24
+ DEFAULT_LOOKUP_FIELD = 'ip'
25
+ DEFAULT_OUTPU_FIELD = 'geoip'
26
+ DEFAULT_FIELD_DELIMITER = '.'
27
+ DEFAULT_FLATTEN = false
28
+
29
+ DEFAULT_LOCALE = 'en'
30
+
31
+ DEFAULT_CITY = true
32
+ DEFAULT_CONTINENT = true
33
+ DEFAULT_COUNTRY = true
34
+ DEFAULT_LOCATION = true
35
+ DEFAULT_POSTAL = false
36
+ DEFAULT_REGISTERED_COUNTRY = false
37
+ DEFAULT_REPRESENTED_COUNTRY = false
38
+ DEFAULT_SUBDIVISIONS = false
39
+ DEFAULT_TRAITS = false
40
+ DEFAULT_CONNECTION_TYPE = false
41
+ DEFAULT_AUTONOMOUS_SYSTEM = true
42
+
43
+ config_param :enable_auto_download, :bool, :default => DEFAULT_ENABLE_DOWNLOAD,
44
+ :desc => 'If true, enable to download GeoIP2 database autometically (default: %s).' % DEFAULT_ENABLE_DOWNLOAD
45
+
46
+ config_param :md5_city_url, :string, :default => DEFAULT_MD5_CITY_URL,
47
+ :desc => 'GeoIP2 MD5 checksum URL (default: %s)' % DEFAULT_MD5_CITY_URL
48
+
49
+ config_param :download_city_url, :string, :default => DEFAULT_DOWNLOAD_CITY_URL,
50
+ :desc => 'GeoIP2 database download URL (default: %s).' % DEFAULT_DOWNLOAD_CITY_URL
51
+
52
+ config_param :md5_city_path, :string, :default => DEFAULT_MD5_CITY_PATH,
53
+ :desc => 'GeoIP2 MD5 checksum path. (default: %s)' % DEFAULT_MD5_CITY_PATH
54
+
55
+ config_param :database_city_path, :string, :default => DEFAULT_DATABASE_CITY_PATH,
56
+ :desc => 'GeoIP2 database path. (default: %s)' % DEFAULT_DATABASE_CITY_PATH
57
+
58
+ config_param :md5_asn_url, :string, :default => DEFAULT_MD5_ASN_URL,
59
+ :desc => 'GeoIP2 MD5 checksum URL (default: %s)' % DEFAULT_MD5_ASN_URL
60
+
61
+ config_param :download_asn_url, :string, :default => DEFAULT_DOWNLOAD_ASN_URL,
62
+ :desc => 'GeoIP2 database download URL (default: %s).' % DEFAULT_DOWNLOAD_ASN_URL
63
+
64
+ config_param :md5_asn_path, :string, :default => DEFAULT_MD5_ASN_PATH,
65
+ :desc => 'GeoIP2 MD5 checksum path. (default: %s)' % DEFAULT_MD5_ASN_PATH
66
+
67
+ config_param :database_asn_path, :string, :default => DEFAULT_DATABASE_ASN_PATH,
68
+ :desc => 'GeoIP2 database path. (default: %s)' % DEFAULT_DATABASE_ASN_PATH
69
+
70
+ config_param :lookup_field, :string, :default => DEFAULT_LOOKUP_FIELD,
71
+ :desc => 'Specify the field name that IP address is stored (default: %s).' % DEFAULT_LOOKUP_FIELD
72
+
73
+ config_param :output_field, :string, :default => DEFAULT_OUTPU_FIELD,
74
+ :desc => 'Specify the field name that store the result (default: %s).' % DEFAULT_OUTPU_FIELD
75
+
76
+ config_param :field_delimiter, :string, :default => DEFAULT_FIELD_DELIMITER,
77
+ :desc => 'Specify the field delimiter (default %s).' % DEFAULT_FIELD_DELIMITER
78
+
79
+ config_param :flatten, :bool, :default => DEFAULT_FLATTEN,
80
+ :desc => 'If true, to flatten the result using field_delimiter (default: %s).' % DEFAULT_FLATTEN
81
+
82
+ config_param :locale, :string, :default => DEFAULT_LOCALE,
83
+ :desc => 'Get the data for the specified locale (default: %s).' % DEFAULT_LOCALE
84
+
85
+ config_param :continent, :bool, :default => DEFAULT_CONTINENT,
86
+ :desc => 'If true, to get continent information (default: %s).' % DEFAULT_CONTINENT
87
+
88
+ config_param :country, :bool, :default => DEFAULT_COUNTRY,
89
+ :desc => 'If true, to get country information (default: %s).' % DEFAULT_COUNTRY
90
+
91
+ config_param :city, :bool, :default => DEFAULT_CITY,
92
+ :desc => 'If true, to get city information (default: %s).' % DEFAULT_CITY
93
+
94
+ config_param :location, :bool, :default => DEFAULT_LOCATION,
95
+ :desc => 'If true, to get location information (default: %s).' % DEFAULT_LOCATION
96
+
97
+ config_param :postal, :bool, :default => DEFAULT_POSTAL,
98
+ :desc => 'If true, to get postal information (default: %s).' % DEFAULT_POSTAL
99
+
100
+ config_param :registered_country, :bool, :default => DEFAULT_REGISTERED_COUNTRY,
101
+ :desc => 'If true, to get registered country information (default: %s).' % DEFAULT_REGISTERED_COUNTRY
102
+
103
+ config_param :represented_country, :bool, :default => DEFAULT_REPRESENTED_COUNTRY,
104
+ :desc => 'If true, to get represented country information (default: %s).' % DEFAULT_REPRESENTED_COUNTRY
105
+
106
+ config_param :subdivisions, :bool, :default => DEFAULT_SUBDIVISIONS,
107
+ :desc => 'If true, to get subdivisions information (default: %s).' % DEFAULT_SUBDIVISIONS
108
+
109
+ config_param :traits, :bool, :default => DEFAULT_TRAITS,
110
+ :desc => 'If true, to get traits information (default: %s).' % DEFAULT_TRAITS
111
+
112
+ config_param :connection_type, :bool, :default => DEFAULT_CONNECTION_TYPE,
113
+ :desc => 'If true, to get connection type information (default: %s).' % DEFAULT_CONNECTION_TYPE
114
+
115
+ config_param :autonomous_system, :bool, :default => DEFAULT_AUTONOMOUS_SYSTEM,
116
+ :desc => 'Autonomous System (default: %s).' % DEFAULT_AUTONOMOUS_SYSTEM
117
+
118
+
119
+
120
+
121
+
122
+ def initialize
123
+ super
124
+ end
125
+
126
+ def configure(conf)
127
+ super
128
+
129
+ if enable_auto_download then
130
+ download_database @download_city_url, @md5_city_url, @database_city_path, @md5_city_path
131
+ download_database @download_asn_url, @md5_asn_url, @database_asn_path, @md5_asn_path
132
+ end
133
+
134
+ @database_city = MaxMindDB.new(@database_city_path)
135
+ @database_asn = MaxMindDB.new(@database_asn_path)
136
+ end
137
+
138
+ def filter(tag, time, record)
139
+ ip = record[@lookup_field]
140
+
141
+ unless ip.nil? then
142
+
143
+ geoip_city = {}
144
+ geoip_asn = {}
145
+ begin
146
+ geoip_city = @database_city.lookup(ip)
147
+ geoip_asn = @database_asn.lookup(ip)
148
+ rescue IPAddr::InvalidAddressError => e
149
+ # Do nothing if if InvalidAddressError
150
+ return record
151
+ end
152
+
153
+ if geoip_city.found? then
154
+
155
+ unless @flatten then
156
+ record.merge!({@output_field => {}})
157
+ end
158
+
159
+ if @continent then
160
+ continent_hash = {}
161
+
162
+ unless geoip_city.continent.code.nil? then
163
+ continent_hash['continent_code'] = geoip_city.continent.code
164
+ end
165
+ unless geoip_city.continent.geoname_id.nil? then
166
+ continent_hash['continent_geoname_id'] = geoip_city.continent.geoname_id
167
+ end
168
+ unless geoip_city.continent.iso_code.nil? then
169
+ continent_hash['continent_iso_code'] = geoip_city.continent.iso_code
170
+ end
171
+ unless geoip_city.continent.name(@locale).nil? then
172
+ continent_hash['continent_name'] = geoip_city.continent.name(@locale)
173
+ end
174
+
175
+ unless continent_hash.empty? then
176
+ if @flatten then
177
+ record.merge!(to_flatten(continent_hash, [@output_field], @field_delimiter))
178
+ else
179
+ record[@output_field].merge!(continent_hash)
180
+ end
181
+ end
182
+ end
183
+
184
+ if @country then
185
+ country_hash = {}
186
+
187
+ unless geoip_city.country.code.nil? then
188
+ country_hash['country_code'] = geoip_city.country.code
189
+ end
190
+ unless geoip_city.country.geoname_id.nil? then
191
+ country_hash['country_geoname_id'] = geoip_city.country.geoname_id
192
+ end
193
+ unless geoip_city.country.iso_code.nil? then
194
+ country_hash['country'] = geoip_city.country.iso_code
195
+ end
196
+ unless geoip_city.country.name(@locale).nil? then
197
+ country_hash['country_name'] = geoip_city.country.name(@locale)
198
+ end
199
+
200
+ unless country_hash.empty? then
201
+ if @flatten then
202
+ record.merge!(to_flatten(country_hash, [@output_field], @field_delimiter))
203
+ else
204
+ record[@output_field].merge!(country_hash)
205
+ end
206
+ end
207
+ end
208
+
209
+ if @city then
210
+ city_hash = {}
211
+
212
+ unless geoip_city.city.code.nil? then
213
+ city_hash['city_code'] = geoip_city.city.code
214
+ end
215
+ unless geoip_city.city.geoname_id.nil? then
216
+ city_hash['city_geoname_id'] = geoip_city.city.geoname_id
217
+ end
218
+ unless geoip_city.city.iso_code.nil? then
219
+ city_hash['city_iso_code'] = geoip_city.city.iso_code
220
+ end
221
+ unless geoip_city.city.name(@locale).nil? then
222
+ city_hash['city'] = geoip_city.city.name(@locale)
223
+ end
224
+
225
+ unless city_hash.empty? then
226
+ if @flatten then
227
+ record.merge!(to_flatten(city_hash, [@output_field], @field_delimiter))
228
+ else
229
+ record[@output_field].merge!(city_hash)
230
+ end
231
+ end
232
+ end
233
+
234
+ if @location then
235
+ location_hash = {}
236
+
237
+ unless geoip_city.location.latitude.nil? or geoip_city.location.longitude.nil? then
238
+ location_hash['location'] = { "lat" => geoip_city.location.latitude, "lon" => geoip_city.location.longitude}
239
+ end
240
+ unless geoip_city.location.latitude.nil? then
241
+ location_hash['latitude'] = geoip_city.location.latitude
242
+ end
243
+ unless geoip_city.location.longitude.nil? then
244
+ location_hash['longitude'] = geoip_city.location.longitude
245
+ end
246
+ unless geoip_city.location.metro_code.nil? then
247
+ location_hash['metro_code'] = geoip_city.location.metro_code
248
+ end
249
+ unless geoip_city.location.time_zone.nil? then
250
+ location_hash['time_zone'] = geoip_city.location.time_zone
251
+ end
252
+
253
+ unless location_hash.empty? then
254
+ if @flatten then
255
+ record.merge!(to_flatten(location_hash, [@output_field], @field_delimiter))
256
+ else
257
+ record[@output_field].merge!(location_hash)
258
+ end
259
+ end
260
+ end
261
+
262
+ if @postal then
263
+ postal_hash = {}
264
+
265
+ unless geoip_city.postal.code.nil? then
266
+ postal_hash['postal_code'] = geoip_city.postal.code
267
+ end
268
+
269
+ unless postal_hash.empty? then
270
+ if @flatten then
271
+ record.merge!(to_flatten(postal_hash, [@output_field], @field_delimiter))
272
+ else
273
+ record[@output_field].merge!(postal_hash)
274
+ end
275
+ end
276
+ end
277
+
278
+ if @registered_country then
279
+ registered_country_hash = {}
280
+
281
+ unless geoip_city.registered_country.code.nil? then
282
+ registered_country_hash['code'] = geoip_city.registered_country.code
283
+ end
284
+ unless geoip_city.registered_country.geoname_id.nil? then
285
+ registered_country_hash['geoname_id'] = geoip_city.registered_country.geoname_id
286
+ end
287
+ unless geoip_city.registered_country.iso_code.nil? then
288
+ registered_country_hash['iso_code'] = geoip_city.registered_country.iso_code
289
+ end
290
+ unless geoip_city.registered_country.name(@locale).nil? then
291
+ registered_country_hash['name'] = geoip_city.registered_country.name(@locale)
292
+ end
293
+
294
+ unless registered_country_hash.empty? then
295
+ if @flatten then
296
+ record.merge!(to_flatten(registered_country_hash, [@output_field, 'registered_country'], @field_delimiter))
297
+ else
298
+ record[@output_field].merge!({'registered_country' => registered_country_hash})
299
+ end
300
+ end
301
+ end
302
+
303
+ if @represented_country then
304
+ represented_country_hash = {}
305
+
306
+ unless geoip_city.represented_country.code.nil? then
307
+ represented_country_hash['code'] = geoip_city.represented_country.code
308
+ end
309
+ unless geoip_city.represented_country.geoname_id.nil? then
310
+ represented_country_hash['geoname_id'] = geoip_city.represented_country.geoname_id
311
+ end
312
+ unless geoip_city.represented_country.iso_code.nil? then
313
+ represented_country_hash['iso_code'] = geoip_city.represented_country.iso_code
314
+ end
315
+ unless geoip_city.represented_country.name(@locale).nil? then
316
+ represented_country_hash['name'] = geoip_city.represented_country.name(@locale)
317
+ end
318
+
319
+ unless represented_country_hash.empty? then
320
+ if @flatten then
321
+ record.merge!(to_flatten(represented_country_hash, [@output_field, 'represented_country'], @field_delimiter))
322
+ else
323
+ record[@output_field].merge!({'represented_country' => represented_country_hash})
324
+ end
325
+ end
326
+ end
327
+
328
+ if @subdivisions then
329
+ subdivision_arry = []
330
+
331
+ i = 0
332
+ geoip_city.subdivisions.each do |subdivision|
333
+ subdivision_hash = {}
334
+
335
+ unless subdivision.code.nil? then
336
+ subdivision_hash['code_%d' % [i]] = subdivision.code
337
+ end
338
+ unless subdivision.geoname_id.nil? then
339
+ subdivision_hash['geoname_id_%d' % [i]] = subdivision.geoname_id
340
+ end
341
+ unless subdivision.iso_code.nil? then
342
+ subdivision_hash['iso_code_%d' % [i]] = subdivision.iso_code
343
+ end
344
+ unless subdivision.name(@locale).nil? then
345
+ subdivision_hash['name_%d' % [i]] = subdivision.name(@locale)
346
+ end
347
+
348
+ unless subdivision_hash.empty? then
349
+ subdivision_arry.push(subdivision_hash)
350
+ end
351
+
352
+ i = i + 1
353
+ end
354
+
355
+ unless subdivision_arry.empty? then
356
+ if @flatten then
357
+ subdivision_arry.each do |subdivision|
358
+ record.merge!(to_flatten(subdivision, [@output_field, 'subdivisions'], @field_delimiter))
359
+ end
360
+ else
361
+ record[@output_field].merge!({'subdivisions' => subdivision_arry})
362
+ end
363
+ end
364
+ end
365
+
366
+ if @traits then
367
+ traits_hash = {}
368
+
369
+ unless geoip_city.traits.is_anonymous_proxy.nil? then
370
+ traits_hash['is_anonymous_proxy'] = geoip_city.traits.is_anonymous_proxy
371
+ end
372
+ unless geoip_city.traits.is_satellite_provider.nil? then
373
+ traits_hash['is_satellite_provider'] = geoip_city.traits.is_satellite_provider
374
+ end
375
+
376
+ unless traits_hash.empty? then
377
+ if @flatten then
378
+ record.merge!(to_flatten(traits_hash, [@output_field, 'traits'], @field_delimiter))
379
+ else
380
+ record[@output_field].merge!({'traits' => traits_hash})
381
+ end
382
+ end
383
+ end
384
+
385
+ if @connection_type then
386
+ unless geoip_city.connection_type.nil? then
387
+ if @flatten then
388
+ record.merge!(to_flatten(geoip_city.connection_type, [@output_field, 'connection_type'], @field_delimiter))
389
+ else
390
+ record[@output_field].merge!({'connection_type' => geoip_city.connection_type})
391
+ end
392
+ end
393
+ end
394
+
395
+ if geoip_asn.found? then
396
+ if @autonomous_system then
397
+ autonomous_system_hash = {}
398
+
399
+ autonomous_system_hash['number'] = geoip_asn['autonomous_system_number']
400
+ autonomous_system_hash['organization'] = geoip_asn['autonomous_system_organization']
401
+
402
+ unless autonomous_system_hash.empty? then
403
+ if @flatten then
404
+ record.merge!(to_flatten(autonomous_system_hash, [@output_field, 'as'], @field_delimiter))
405
+ else
406
+ record[@output_field].merge!({'as' => autonomous_system_hash})
407
+ end
408
+ end
409
+ end
410
+ end
411
+
412
+ log.debug "Record: %s" % record.inspect
413
+ else
414
+ log.debug "It was not possible to look up the #{ip}."
415
+ end
416
+ end
417
+
418
+ return record
419
+ end
420
+
421
+ def to_flatten(hash, stack=[], delimiter='/')
422
+ output = {}
423
+
424
+ hash.keys.each do |key|
425
+ stack.push key
426
+
427
+ if hash[key].instance_of?(Hash) then
428
+ output.merge!(to_flatten(hash[key], stack, delimiter))
429
+ else
430
+ output[stack.join(delimiter)] = hash[key]
431
+ end
432
+
433
+ stack.pop
434
+ end
435
+
436
+ return output
437
+ end
438
+
439
+ def download_database(download_url, md5_url, database_path, md5_path)
440
+ # database directory
441
+ database_dir = File.dirname database_path
442
+ md5_dir = File.dirname md5_path
443
+
444
+ # create database directory if directory does not exist.
445
+ FileUtils.mkdir_p(database_dir) unless File.exist?(database_dir)
446
+ FileUtils.mkdir_p(md5_dir) unless File.exist?(md5_dir)
447
+
448
+ # create empty md5 file if file does not exist.
449
+ File.open(md5_path, 'wb').close() unless File.exist?(md5_path)
450
+
451
+ # read saved md5
452
+ current_md5 = nil
453
+ begin
454
+ open(md5_path, 'rb') do |data|
455
+ current_md5 = data.read
456
+ end
457
+ log.info "Current MD5: %s" % current_md5
458
+ rescue => e
459
+ log.warn e.message
460
+ end
461
+
462
+ # fetch md5
463
+ fetched_md5 = nil
464
+ begin
465
+ open(md5_url, 'rb') do |data|
466
+ fetched_md5 = data.read
467
+ end
468
+ log.info "Fetched MD5: %s" % fetched_md5
469
+ rescue => e
470
+ log.warn e.message
471
+ end
472
+
473
+ # check md5
474
+ unless current_md5 == fetched_md5 then
475
+ # download new database
476
+ download_path = database_dir + '/' + File.basename(download_url)
477
+ begin
478
+ log.info "Download: %s" % download_url
479
+ open(download_path, 'wb') do |output|
480
+ open(download_url, 'rb') do |data|
481
+ output.write(data.read)
482
+ end
483
+ end
484
+ log.info "Download done: %s" % download_path
485
+ rescue => e
486
+ log.warn e.message
487
+ end
488
+
489
+ # unzip new database temporaly
490
+ tmp_database_path = database_dir + '/tmp_' + File.basename(database_path)
491
+ log.info "temp_database_path: %s" % tmp_database_path
492
+ log.info "PWD %s" % File.expand_path(tmp_database_path)
493
+ begin
494
+ log.info "Unzip: %s" % download_path
495
+ Zlib::GzipReader.open(download_path) do |gz|
496
+ Archive::Tar::Minitar.unpack(gz, './tmp')
497
+ end
498
+ src_path = Dir.glob('./tmp/' + File.basename(download_path, ".tar.gz") + '_*/' + File.basename(download_path, ".tar.gz") + '.mmdb')
499
+ FileUtils.mv(src_path, database_dir)
500
+ FileUtils.rm_rf('./tmp')
501
+ log.info "Unzip done: %s" % tmp_database_path
502
+ rescue => e
503
+ puts e.message
504
+ end
505
+
506
+ # check mkd5
507
+ temp_md5 = Digest::MD5.hexdigest(File.open(download_path, 'rb').read)
508
+ log.info "New MD5: %s" % temp_md5
509
+ if fetched_md5 == temp_md5 then
510
+ # record new md5
511
+ log.info "Save: %s" % md5_path
512
+ File.write(md5_path, fetched_md5)
513
+ log.info "Save done: %s" % md5_path
514
+ else
515
+ log.info "MD5 missmatch: Fetched MD5 (%s) != New MD5 (%s) ; " % [fetched_md5, temp_md5]
516
+ end
517
+ end
518
+ end
519
+ end
520
+ end
metadata ADDED
@@ -0,0 +1,136 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluent-plugin-filter-geoip2
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.4
5
+ platform: ruby
6
+ authors:
7
+ - imcotop SOC
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2023-06-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: fluentd
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.12.32
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.12.32
27
+ - !ruby/object:Gem::Dependency
28
+ name: maxminddb
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.1.11
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.1.11
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 1.14.6
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 1.14.6
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 11.1.2
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 11.1.2
69
+ - !ruby/object:Gem::Dependency
70
+ name: test-unit
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 3.1.5
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 3.1.5
83
+ - !ruby/object:Gem::Dependency
84
+ name: minitest
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 5.8.3
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 5.8.3
97
+ description: Fluent filter plugin for adding GeoIP data to record. Supports the new
98
+ Maxmind v2 database formats.
99
+ email:
100
+ - imcotop@icloud.com
101
+ executables: []
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - ".gitignore"
106
+ - Gemfile
107
+ - LICENSE
108
+ - README.md
109
+ - Rakefile
110
+ - fluent-plugin-filter-geoip2.gemspec
111
+ - fluent.conf
112
+ - lib/fluent/plugin/filter_geoip2.rb
113
+ homepage: https://github.com/OlehPalanskyi/fluent-plugin-filter-geoip2
114
+ licenses:
115
+ - Apache-2.0
116
+ metadata: {}
117
+ post_install_message:
118
+ rdoc_options: []
119
+ require_paths:
120
+ - lib
121
+ required_ruby_version: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ required_rubygems_version: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
131
+ requirements: []
132
+ rubygems_version: 3.2.5
133
+ signing_key:
134
+ specification_version: 4
135
+ summary: Fluent filter plugin for adding GeoIP data to record.
136
+ test_files: []