fluent-plugin-geoip-kk 1.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ed458000a7ed8af776a38bf822027286ea3770a8f0b5668083419bd79516304b
4
+ data.tar.gz: d988309e6a245f51bf670bbc8d6d42dfafb087546a0ccb183e55a3926adb6459
5
+ SHA512:
6
+ metadata.gz: e45cca487405e1c11fb97a3866f9f9c5d20d724ee4285432b78b1ed097de16464532455972ee7222a8b1d3d538d95e849c899bc5b8bfc8501e6d76b24a6e508b
7
+ data.tar.gz: dc58642c973dbd96d887fc1160521feaa84372697dfbe812043bc9f11763cfa03551b0095bec43f284fd2fa5029f5590321668fd43bb31229dfcf73d937a4777
data/.gitattributes ADDED
@@ -0,0 +1 @@
1
+ *.dat filter=lfs diff=lfs merge=lfs -text
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in fluent-plugin-geoip-kk.gemspec
6
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2015 Yuri UMEZAKI
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,121 @@
1
+ # fluent-plugin-geoip-kk
2
+
3
+ [Fluentd](http://fluentd.org) filter plugin to add geoip.
4
+
5
+
6
+ ## Requirements
7
+
8
+ | fluent-plugin-geoip-kk | fluentd | ruby |
9
+ |----------------------------|------------|--------|
10
+ | >= 1.0.0 | >= v0.14.0 | >= 2.1 |
11
+ | < 1.0.0 | >= v0.12.0 | >= 1.9 |
12
+
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ # for fluentd
18
+ $ gem install fluent-plugin-geoip-kk
19
+
20
+ # for td-agent2
21
+ $ sudo td-agent-gem install fluent-plugin-geoip-kk
22
+ ```
23
+
24
+
25
+ ## Usage
26
+
27
+ ### Example 1:
28
+
29
+ ```xml
30
+ <filter access.nginx.**>
31
+ @type geoip
32
+ # key_name client_ip
33
+ # database_path /data/geoip/GeoLite2-City.mmdb
34
+ # out_key geo
35
+ </filter>
36
+ ```
37
+
38
+ Assuming following inputs are coming:
39
+
40
+ ```json
41
+ access.nginx: {
42
+ "client_ip":"93.184.216.34",
43
+ "scheme":"http", "method":"GET", "host":"example.com",
44
+ "path":"/", "query":"-", "req_bytes":200, "referer":"-",
45
+ "status":200, "res_bytes":800, "res_body_bytes":600, "taken_time":0.001, "user_agent":"Mozilla/5.0"
46
+ }
47
+ ```
48
+
49
+ then output bocomes as belows:
50
+
51
+ ```json
52
+ access.nginx: {
53
+ "client_ip":"93.184.216.34",
54
+ "scheme":"http", "method":"GET", "host":"example.com",
55
+ "path":"/", "query":"-", "req_bytes":200, "referer":"-",
56
+ "status":200, "res_bytes":800, "res_body_bytes":600, "taken_time":0.001, "user_agent":"Mozilla/5.0",
57
+ "geo": {
58
+ "coordinates": [-70.8228, 42.150800000000004],
59
+ "country_code": "US",
60
+ "city": "Norwell",
61
+ "region_code": "MA",
62
+ }
63
+ }
64
+ ```
65
+
66
+
67
+ ## Parameters
68
+ - key_name *field_key*
69
+
70
+ Target key name. default client_ip.
71
+
72
+ - out_key *string*
73
+
74
+ Output prefix key name. default geo.
75
+
76
+ - database_path *file_path*
77
+
78
+ Database file(GeoIPCity.dat) path.
79
+ Get from [MaxMind](http://dev.maxmind.com/geoip/legacy/geolite/)
80
+
81
+ - flatten *bool*
82
+ join hashed data by '_'. default false.
83
+
84
+
85
+ ## VS.
86
+ [fluent-plugin-geoip](https://github.com/y-ken/fluent-plugin-geoip)
87
+ Fluentd output plugin to geolocate with geoip.
88
+ It is able to customize fields with placeholder.
89
+
90
+ * Easy to install.
91
+ * Not require to install Development Tools and geoip-dev library.
92
+ * ( fluent-plugin-geoip use geoip-c gem but our plugin use geoip. It's conflict. )
93
+ * 5-10 times faster by the LRU cache.
94
+ * See [benchmark](test/bench_geoip_filter.rb).
95
+
96
+
97
+ ## TODO
98
+
99
+ * patches welcome!
100
+
101
+
102
+ ## Contributing
103
+
104
+ 1. Fork it ( https://github.com/bungoume/fluent-plugin-geoip-filter/fork )
105
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
106
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
107
+ 4. Push to the branch (`git push origin my-new-feature`)
108
+ 5. Create a new Pull Request
109
+
110
+
111
+ ## Copyright
112
+
113
+ Copyright (c) 2015 Yuri Umezaki
114
+
115
+
116
+ ## License
117
+
118
+ [Apache License, Version 2.0.](http://www.apache.org/licenses/LICENSE-2.0)
119
+
120
+ This product includes GeoLite data created by MaxMind, available from
121
+ [http://www.maxmind.com](http://www.maxmind.com).
data/Rakefile ADDED
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rake/testtask'
5
+
6
+ task default: :push
7
+
8
+ Rake::TestTask.new(:test) do |test|
9
+ test.libs << 'lib' << 'test'
10
+ test.pattern = 'test/**/test_*.rb'
11
+ test.verbose = true
12
+ end
13
+
14
+ task :push do
15
+ system 'git add .'
16
+ system "git commit -m 'Update #{Time.now}.'"
17
+ system 'git pull'
18
+ system 'git push origin main'
19
+ end
Binary file
@@ -0,0 +1,3 @@
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:25bce9e7f5fe9ffd12afa663c2e57b311a4286549a858965c4ff01596f604c8a
3
+ size 19148749
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'fluent-plugin-geoip-kk'
8
+ spec.version = '1.0.0'
9
+ spec.authors = ['kevin197011']
10
+ spec.email = ['kevin197011@outlook.com']
11
+ spec.homepage = 'https://github.com/kevin197011/fluent-plugin-geoip-kk'
12
+ spec.summary = 'Fluentd filter plugin to add geoip'
13
+ spec.description = spec.summary
14
+ spec.license = 'Apache-2.0'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_runtime_dependency 'fluentd', ['>= 0.14.0', '< 2']
22
+ spec.add_runtime_dependency 'geoip', '>= 0.1.22'
23
+ spec.add_runtime_dependency 'lru_redux', '>= 1.0.0'
24
+ spec.add_runtime_dependency 'maxminddb', '>= 1.5.0'
25
+ spec.add_development_dependency 'bundler'
26
+ spec.add_development_dependency 'rake'
27
+ spec.add_development_dependency 'test-unit' if defined?(RUBY_VERSION) && RUBY_VERSION > '2.2'
28
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'maxminddb'
4
+ require 'lru_redux'
5
+ require 'fluent/plugin/filter'
6
+
7
+ module Fluent
8
+ module Plugin
9
+ class GeoipFilter < Filter
10
+ Fluent::Plugin.register_filter('geoip', self)
11
+
12
+ def initialize
13
+ @geoip_cache = LruRedux::Cache.new(8192)
14
+ super
15
+ end
16
+
17
+ config_param :database_path, :string, default: "#{File.dirname(__FILE__)}/../../../data/GeoLite2-City.mmdb"
18
+ config_param :key_name, :string, default: 'client_ip'
19
+ config_param :out_key, :string, default: 'geo'
20
+ config_param :flatten, :bool, default: false
21
+
22
+ def configure(conf)
23
+ super
24
+ begin
25
+ @geoip = MaxMindDB.new(@database_path)
26
+ rescue StandardError => e
27
+ log.warn 'Failed to configure parser. Use default pattern.', error_class: e.class, error: e.message
28
+ log.warn_backtrace
29
+ end
30
+ end
31
+
32
+ def filter(_tag, _time, record)
33
+ ip_addr = record[@key_name]
34
+
35
+ return record if ip_addr.nil? || ip_addr == '-'
36
+
37
+ geo_ip = @geoip_cache.getset(ip_addr) { get_geoip(ip_addr) }
38
+
39
+ if flatten
40
+ record.merge! hash_flatten(geo_ip, [@out_key])
41
+ else
42
+ record[@out_key] = geo_ip
43
+ end
44
+
45
+ record
46
+ end
47
+
48
+ private
49
+
50
+ def get_geoip(ip_addr)
51
+ geo_ip = @geoip.lookup(ip_addr)
52
+ data = {}
53
+ return data if geo_ip.nil? || ip_addr == '-'
54
+
55
+ data['coordinates'] = [geo_ip.location.longitude, geo_ip.location.latitude] if geo_ip.location
56
+ data['country_code'] = geo_ip.country.iso_code if geo_ip.country
57
+ data['city'] = geo_ip.city.name if geo_ip.city
58
+ data['region_code'] = geo_ip.subdivisions.first.iso_code if geo_ip.subdivisions.any?
59
+ data
60
+ end
61
+
62
+ def hash_flatten(a, keys = [])
63
+ ret = {}
64
+ a.each do |k, v|
65
+ ks = keys + [k]
66
+ if v.instance_of?(Hash)
67
+ ret.merge!(hash_flatten(v, ks))
68
+ else
69
+ ret.merge!({ ks.join('_') => v })
70
+ end
71
+ end
72
+ ret
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'helper'
4
+ require 'fluent/plugin/filter_geoip'
5
+
6
+ # setup
7
+ Fluent::Test.setup
8
+ config = %(
9
+ @type geoip
10
+ out_key geo
11
+ )
12
+ time = Time.now.to_i
13
+ tag = 'foo.bar'
14
+ driver = Fluent::Test::FilterTestDriver.new(Fluent::GeoipFilter, tag).configure(config, true)
15
+
16
+ # bench
17
+ require 'benchmark'
18
+ require 'ipaddr'
19
+ n = 100_000
20
+ Benchmark.bm(7) do |x|
21
+ # 8192 random IP
22
+ x.report do
23
+ driver.run do
24
+ n.times do
25
+ driver.emit({ 'client_ip' => IPAddr.new(rand(2**13) * 2**19, Socket::AF_INET).to_s }, time)
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ # Without LRU cache
32
+ # user system total real
33
+ # 11.410000 2.730000 14.140000 ( 15.431248)
34
+ # With LRU cache(8192) & random 1024 IP
35
+ # user system total real
36
+ # 1.250000 0.070000 1.320000 ( 1.322339)
37
+ # With LRU cache(8192) & random 8192 IP
38
+ # user system total real
39
+ # 1.890000 0.210000 2.100000 ( 2.102445)
40
+ # With LRU cache(8192) & random 16384 IP
41
+ # user system total real
42
+ # 8.450000 2.070000 10.520000 ( 12.170379)
43
+ # With LRU cache(8192) & random 65536 IP
44
+ # user system total real
45
+ # 11.890000 2.820000 14.710000 ( 16.051674)
46
+
47
+ # fluent-plugin-geoip
48
+ # (https://github.com/y-ken/fluent-plugin-geoip)
49
+ # user system total real
50
+ # 11.540000 0.270000 11.810000 ( 12.685000)
data/test/helper.rb ADDED
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ warn e.message
9
+ warn 'Run `bundle install` to install missing gems'
10
+ exit e.status_code
11
+ end
12
+ require 'test/unit'
13
+
14
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
15
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
16
+ require 'fluent/test'
17
+ unless ENV.key?('VERBOSE')
18
+ nulllogger = Object.new
19
+ nulllogger.instance_eval do |_obj|
20
+ def method_missing(method, *args)
21
+ # pass
22
+ end
23
+ end
24
+ $log = nulllogger
25
+ end
26
+ require 'fluent/test/helpers'
27
+ require 'fluent/test/driver/filter'
28
+ require 'fluent/plugin/filter_geoip'
29
+
30
+ module Test
31
+ module Unit
32
+ class TestCase
33
+ include Fluent::Test::Helpers
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'helper'
4
+
5
+ class GeoipFilterTest < Test::Unit::TestCase
6
+ def setup
7
+ Fluent::Test.setup
8
+ end
9
+
10
+ CONFIG = %(
11
+ @type geoip
12
+ key_name client_ip
13
+ out_key geo
14
+ )
15
+
16
+ def create_driver(conf = CONFIG)
17
+ Fluent::Test::Driver::Filter.new(Fluent::Plugin::GeoipFilter).configure(conf)
18
+ end
19
+
20
+ def test_configure
21
+ d = create_driver(CONFIG)
22
+ assert_equal 'client_ip', d.instance.config['key_name']
23
+ assert_equal 'geo', d.instance.config['out_key']
24
+ end
25
+
26
+ def test_emit
27
+ d1 = create_driver(CONFIG)
28
+ ip_iddr = '93.184.216.34'
29
+
30
+ d1.run(default_tag: 'test') do
31
+ d1.feed({ 'client_ip' => ip_iddr })
32
+ end
33
+ emits = d1.filtered
34
+ assert_equal 1, emits.length
35
+ geo_object = emits[0][1]['geo']
36
+ assert_equal [-70.8228, 42.150800000000004], geo_object['coordinates']
37
+ assert_equal 'US', geo_object['country_code']
38
+ assert_equal 'Norwell', geo_object['city']
39
+ assert_equal 'MA', geo_object['region_code']
40
+ end
41
+
42
+ def test_emit_flatten
43
+ d1 = create_driver(%(
44
+ @type geoip
45
+ key_name ip_iddr
46
+ flatten
47
+ ))
48
+ ip_iddr = '93.184.216.34'
49
+
50
+ d1.run(default_tag: 'test') do
51
+ d1.feed({ 'ip_iddr' => ip_iddr })
52
+ end
53
+
54
+ emits = d1.filtered
55
+ assert_equal 1, emits.length
56
+ geo_object = emits[0][1]
57
+ assert_equal [-70.8228, 42.150800000000004], geo_object['geo_coordinates']
58
+ assert_equal 'US', geo_object['geo_country_code']
59
+ assert_equal 'Norwell', geo_object['geo_city']
60
+ assert_equal 'MA', geo_object['geo_region_code']
61
+ end
62
+ end
data/test.rb ADDED
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'maxminddb'
4
+
5
+ db = MaxMindDB.new('data/GeoLite2-City.mmdb')
6
+
7
+ ip = '128.101.101.101'
8
+
9
+ begin
10
+ result = db.lookup(ip)
11
+
12
+ puts "IP: #{ip}"
13
+ puts "Country: #{result.country.name}"
14
+ puts "City: #{result.city.name}" if result.city.name
15
+ puts "Latitude: #{result.location.latitude}" if result.location.latitude
16
+ puts "Longitude: #{result.location.longitude}" if result.location.longitude
17
+ puts result.inspect
18
+ rescue MaxMindDB::AddressNotFoundError
19
+ puts 'IP address not found in the database.'
20
+ end
metadata ADDED
@@ -0,0 +1,164 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluent-plugin-geoip-kk
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - kevin197011
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-12-06 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.14.0
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '2'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: 0.14.0
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '2'
33
+ - !ruby/object:Gem::Dependency
34
+ name: geoip
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: 0.1.22
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 0.1.22
47
+ - !ruby/object:Gem::Dependency
48
+ name: lru_redux
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 1.0.0
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: 1.0.0
61
+ - !ruby/object:Gem::Dependency
62
+ name: maxminddb
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: 1.5.0
68
+ type: :runtime
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: 1.5.0
75
+ - !ruby/object:Gem::Dependency
76
+ name: bundler
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ - !ruby/object:Gem::Dependency
90
+ name: rake
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ - !ruby/object:Gem::Dependency
104
+ name: test-unit
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ description: Fluentd filter plugin to add geoip
118
+ email:
119
+ - kevin197011@outlook.com
120
+ executables: []
121
+ extensions: []
122
+ extra_rdoc_files: []
123
+ files:
124
+ - ".gitattributes"
125
+ - ".gitignore"
126
+ - Gemfile
127
+ - LICENSE
128
+ - README.md
129
+ - Rakefile
130
+ - data/GeoLite2-City.mmdb
131
+ - data/GeoLiteCity.dat
132
+ - fluent-plugin-geoip-kk.gemspec
133
+ - lib/fluent/plugin/filter_geoip.rb
134
+ - test.rb
135
+ - test/bench_geoip_filter.rb
136
+ - test/helper.rb
137
+ - test/plugin/test_filter_geoip.rb
138
+ homepage: https://github.com/kevin197011/fluent-plugin-geoip-kk
139
+ licenses:
140
+ - Apache-2.0
141
+ metadata: {}
142
+ post_install_message:
143
+ rdoc_options: []
144
+ require_paths:
145
+ - lib
146
+ required_ruby_version: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - ">="
149
+ - !ruby/object:Gem::Version
150
+ version: '0'
151
+ required_rubygems_version: !ruby/object:Gem::Requirement
152
+ requirements:
153
+ - - ">="
154
+ - !ruby/object:Gem::Version
155
+ version: '0'
156
+ requirements: []
157
+ rubygems_version: 3.5.18
158
+ signing_key:
159
+ specification_version: 4
160
+ summary: Fluentd filter plugin to add geoip
161
+ test_files:
162
+ - test/bench_geoip_filter.rb
163
+ - test/helper.rb
164
+ - test/plugin/test_filter_geoip.rb