fluent-plugin-ipinfo 1.0.2 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5b7f4f8cb5ce41b6e9406b3dd3f88b737f4c25e7b727f9ad05027f83dceebab3
4
- data.tar.gz: aad770ddea261401fb88e81eeecbf411e894ecfb6e8d5b1174dfdd0092f07c3a
3
+ metadata.gz: 2e715ffb9f1f67768b47a75a2909da48be93f43c882d78e135d69c70a3dc9678
4
+ data.tar.gz: 3c002e087f57d526771d43408f2692a0c459b4b266a14623f655d19e83fc79d8
5
5
  SHA512:
6
- metadata.gz: 3476241da4cb77bf3b9a444f0f68041694685b7b2be85b27a2e663f6c113df2156385784f748771baaf9a084bd4a2580d561d9d97de273cc75f9560e10947bce
7
- data.tar.gz: 6833261bdfe609470cd168556ee5075b3e307b53dbd4f5d7c186617e0c50cc09d2466dc54466b7e0d60739b4c01b40d4f64fecb1be17196127825a4fe0199b5e
6
+ metadata.gz: f9269e76e2018277b28e2572b540612fa968d7ebb71ea2e60580f762f3bdfbed5c5aa83d799a4b9ac085c6ffca07a451be4cf01988ce5c5e6409ee421e9031e2
7
+ data.tar.gz: 07210a8a3082bfe1ce5dfb47d0433deb9157d7aaeff4e03b7e3bdb90233e4535547ade6c9d4ad229f11ce0506c1cd926ffcf7f1540aea98b4cfa1ab08d73ae6b
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- fluent-plugin-ipinfo (1.0.2)
4
+ fluent-plugin-ipinfo (1.1.0)
5
5
  IPinfo (~> 1.0, >= 1.0.1)
6
6
  fluentd (>= 0.14.2, < 2)
7
7
 
data/README.md CHANGED
@@ -39,7 +39,7 @@ In this example, the following event:
39
39
  }
40
40
  ```
41
41
 
42
- Would be enriched and returned as following:
42
+ would be enriched and returned as following:
43
43
 
44
44
  ```json
45
45
  {
@@ -68,6 +68,8 @@ Would be enriched and returned as following:
68
68
  The token to be used with the IPInfo API for paid plans.
69
69
  To use the free plan (limited to 50k requests per month), do not use the `access_token` parameter.
70
70
 
71
+ If the value provided for `access_token` is an empty string (`""` or `" "`), the default value (`nil`) is used instead.
72
+
71
73
  ### `key_name`
72
74
 
73
75
  | type | required | default |
@@ -76,6 +78,8 @@ To use the free plan (limited to 50k requests per month), do not use the `access
76
78
 
77
79
  The name of the key containing the IP address.
78
80
 
81
+ If the value provided for `key_name` is an empty string (`""` or `" "`) or `nil`, the default value (`ip_address`) is used instead.
82
+
79
83
  ### `out_key`
80
84
 
81
85
  | type | required | default |
@@ -84,6 +88,46 @@ The name of the key containing the IP address.
84
88
 
85
89
  The name of the key to store the geographical location data in.
86
90
 
91
+ If the value provided for `out_key` is an empty string (`""` or `" "`) or `nil`, the default value (`ipinfo`) is used instead.
92
+
93
+ If the record has already a key with the same name as the value of `out_key`, its value will be overwritten with the geographical location data as shown in the example below:
94
+
95
+ ```xml
96
+ <filter foo.bar>
97
+ @type ipinfo
98
+ access_token 1a2b3c4d5e
99
+ key_name ip_address
100
+ out_key data
101
+ fields ["country_name", "region", "city", "latitude", "longitude"]
102
+ </filter>
103
+ ```
104
+
105
+ The following event:
106
+
107
+ ```json
108
+ {
109
+ "message":"Can you get me the geographical location for this IP addresse ?",
110
+ "ip_address":"8.8.8.8",
111
+ "data": "This value is going to be overwritten."
112
+ }
113
+ ```
114
+
115
+ would be enriched and returned as following:
116
+
117
+ ```json
118
+ {
119
+ "message": "Can you get me the geographical location for this IP addresse ?",
120
+ "ip_address": "8.8.8.8",
121
+ "data": {
122
+ "country_name": "United States",
123
+ "region": "California",
124
+ "city": "Mountain View",
125
+ "latitude": "37.4056",
126
+ "longitude": "-122.0775"
127
+ }
128
+ }
129
+ ```
130
+
87
131
  ### `fields`
88
132
 
89
133
  | type | required | default |
@@ -2,7 +2,7 @@ $:.push File.expand_path("../lib", __FILE__)
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "fluent-plugin-ipinfo"
5
- s.version = "1.0.2"
5
+ s.version = "1.1.0"
6
6
  s.license = "Apache-2.0"
7
7
  s.authors = ["Ahmed Abdelkafi"]
8
8
  s.email = ["abdelkafiahmed@gmail.com"]
@@ -35,41 +35,76 @@ module Fluent::Plugin
35
35
 
36
36
  def initialize
37
37
  super
38
- # "maxsize": 4096 # Number of entries to keep in cache
39
- # "ttl": 60 * 60 * 24 * 7 # Keep the data in cache for one week
40
- @ipinfo_settings = {:ttl => 604800, :maxsize => 4096}
38
+ # Keep the data in cache for one week
39
+ # Number of entries to keep in cache
40
+ @ipinfo_cache_settings = {:ttl => 60 * 60 * 24 * 7, :maxsize => 4096}
41
41
  end
42
42
 
43
43
  def configure(conf)
44
44
  super
45
+
46
+ if !@access_token.nil? and @access_token.strip.empty?
47
+ log.warn "access_token value is an empty string. Falling back to default value."
48
+ @access_token = nil
49
+ end
50
+
51
+ if @key_name.nil? or @key_name.strip.empty?
52
+ log.warn "key_name value is '#{@key_name}'. Falling back to default value."
53
+ @key_name = 'ip_address'
54
+ end
55
+
56
+ if @out_key.nil? or @out_key.strip.empty?
57
+ log.warn "out_key value is '#{@out_key}'. Falling back to default value."
58
+ @out_key = 'ipinfo'
59
+ end
60
+
61
+ # Delete duplicates and empty fields (nil values included)
62
+ @fields = @fields.uniq.delete_if {|f| f.strip.empty? or f.nil?}
63
+
64
+ unless @fields.length() > 0
65
+ raise Fluent::ConfigError, "Fields array is empty. You need to specify at least one field."
66
+ end
67
+
68
+ # Create the IPInfo client handler
45
69
  unless @access_token.nil?
46
- @ipinfo_handler = IPinfo::create(@access_token, @ipinfo_settings)
70
+ @ipinfo_handler = IPinfo::create(@access_token, @ipinfo_cache_settings)
47
71
  else
48
- @ipinfo_handler = IPinfo::create(nil, @ipinfo_settings)
72
+ @ipinfo_handler = IPinfo::create(nil, @ipinfo_cache_settings)
49
73
  end
50
74
  end
51
75
 
52
76
  def filter(tag, time, record)
53
- ip_address = record[@key_name]
54
- unless ip_address.nil?
55
- # Fetch geolocation details using IPInfo API
56
- ipinfo_details = @ipinfo_handler.details(ip_address)
57
- # IPInfo ruby wrapper returns a dict based on symbols, we need to stringify the symbols
58
- # to be able to use them easily
59
- all_details = ipinfo_details.all
60
- geodata = all_details.stringify_keys
61
- # Get the final list of fields by running a join operation on the fields provided by the user and the ones
62
- # returned by IPInfo API
63
- ipinfo_returned_fields = geodata.keys
64
- final_fields = ipinfo_returned_fields & @fields
65
- if final_fields.length() != @fields.length()
66
- ignored_fields = @fields - final_fields
67
- ignored_fields.each{|field|
68
- log.warn "Field \"" + field + "\" not present in IPInfo payload. Ignoring it."
69
- }
77
+ # Check that the record has a key whose name is the value of @key_name
78
+ unless record.key?(@key_name)
79
+ log.error "key '#{@key_name}' is not present in the record. Ignoring the record."
80
+ else
81
+ ip_address = record[@key_name]
82
+ # Check that the ip_address is not 'nil'
83
+ unless ip_address.nil?
84
+ begin
85
+ # Fetch geolocation details using IPInfo API
86
+ ipinfo_details = @ipinfo_handler.details(ip_address)
87
+ # IPInfo ruby wrapper returns a dict based on symbols, we need to stringify the symbols
88
+ # to be able to use them easily
89
+ all_details = ipinfo_details.all
90
+ geodata = all_details.stringify_keys
91
+ # Get the final list of fields by running a join operation on the fields provided by the user and the ones
92
+ # returned by IPInfo API
93
+ ipinfo_returned_fields = geodata.keys
94
+ final_fields = ipinfo_returned_fields & @fields
95
+ if final_fields.length() != @fields.length()
96
+ ignored_fields = @fields - final_fields
97
+ ignored_fields.each{|field|
98
+ log.warn "Field '#{@field}' not present in IPInfo payload. Ignoring it."
99
+ }
100
+ end
101
+ # Extract a subhash from the geolocation data returned by IPInfo API using the final_fields list as keys.
102
+ record[@out_key] = extract_subhash(geodata, final_fields)
103
+ rescue Exception => e
104
+ log.error 'An error occured while fetching geographical location data.', error: e
105
+ log.warn_backtrace e.backtrace
106
+ end
70
107
  end
71
- # Extract a subhash from the geolocation data returned by IPInfo API using the final_fields list as keys.
72
- record[@out_key] = extract_subhash(geodata, final_fields)
73
108
  end
74
109
  record
75
110
  end
@@ -51,14 +51,105 @@ class IPinfoFilterTest < Test::Unit::TestCase
51
51
  d.filtered_records
52
52
  end
53
53
 
54
+ sub_test_case 'plugin will use default values' do
55
+ test 'access_token nil' do
56
+ config = %[
57
+ @type ipinfo
58
+ access_token
59
+ ]
60
+ d = create_driver(config)
61
+ assert_equal d.instance.access_token, nil
62
+ end
63
+
64
+ test 'access_token empty string' do
65
+ config = %[
66
+ @type ipinfo
67
+ access_token ""
68
+ ]
69
+ d = create_driver(config)
70
+ assert_equal d.instance.access_token, nil
71
+ end
72
+
73
+ test 'key_name nil' do
74
+ config = %[
75
+ @type ipinfo
76
+ key_name
77
+ ]
78
+ d = create_driver(config)
79
+ assert_equal d.instance.key_name, 'ip_address'
80
+ end
81
+
82
+ test 'key_name empty string' do
83
+ config = %[
84
+ @type ipinfo
85
+ key_name
86
+ ]
87
+ d = create_driver(config)
88
+ assert_equal d.instance.key_name, 'ip_address'
89
+ end
90
+
91
+ test 'out_key nil' do
92
+ config = %[
93
+ @type ipinfo
94
+ out_key
95
+ ]
96
+ d = create_driver(config)
97
+ assert_equal d.instance.out_key, 'ipinfo'
98
+ end
99
+
100
+ test 'out_key empty string' do
101
+ config = %[
102
+ @type ipinfo
103
+ out_key
104
+ ]
105
+ d = create_driver(config)
106
+ assert_equal d.instance.out_key, 'ipinfo'
107
+ end
108
+ end
109
+
110
+ sub_test_case 'plugin will raise Fluent::ConfigError' do
111
+ test 'empty fields' do
112
+ config = %[
113
+ @type ipinfo
114
+ fields []
115
+ ]
116
+ assert_raise Fluent::ConfigError do
117
+ create_driver(config)
118
+ end
119
+ end
120
+
121
+ test 'fields with one empty string' do
122
+ config = %[
123
+ @type ipinfo
124
+ fields [""]
125
+ ]
126
+ assert_raise Fluent::ConfigError do
127
+ create_driver(config)
128
+ end
129
+ end
130
+
131
+ test 'fields with multiple empty string' do
132
+ config = %[
133
+ @type ipinfo
134
+ fields [""]
135
+ ]
136
+ assert_raise Fluent::ConfigError do
137
+ create_driver(config)
138
+ end
139
+ end
140
+ end
141
+
54
142
  sub_test_case 'plugin will fetch geolocation data' do
55
143
  test 'add ipinfo to record with default fields' do
56
- conf = CONFIG
144
+ config = CONFIG
57
145
  messages = [
58
- { 'ip_address' => '8.8.8.8' }
146
+ {
147
+ 'ip_address' => '8.8.8.8'
148
+ }
59
149
  ]
60
150
  expected = [
61
- { 'ip_address' => '8.8.8.8',
151
+ {
152
+ 'ip_address' => '8.8.8.8',
62
153
  'ipinfo' => {
63
154
  'country_name' => 'United States',
64
155
  'region' => 'California',
@@ -68,20 +159,23 @@ class IPinfoFilterTest < Test::Unit::TestCase
68
159
  }
69
160
  }
70
161
  ]
71
- filtered_records = filter(conf, messages)
162
+ filtered_records = filter(config, messages)
72
163
  assert_equal(expected, filtered_records)
73
164
  end
74
165
 
75
166
  test 'add ipinfo to record with custom key_name' do
76
- conf = %[
167
+ config = %[
77
168
  @type ipinfo
78
169
  key_name ip
79
170
  ]
80
171
  messages = [
81
- { 'ip' => '8.8.8.8' }
172
+ {
173
+ 'ip' => '8.8.8.8'
174
+ }
82
175
  ]
83
176
  expected = [
84
- { 'ip' => '8.8.8.8',
177
+ {
178
+ 'ip' => '8.8.8.8',
85
179
  'ipinfo' => {
86
180
  'country_name' => 'United States',
87
181
  'region' => 'California',
@@ -91,20 +185,23 @@ class IPinfoFilterTest < Test::Unit::TestCase
91
185
  }
92
186
  }
93
187
  ]
94
- filtered_records = filter(conf, messages)
188
+ filtered_records = filter(config, messages)
95
189
  assert_equal(expected, filtered_records)
96
190
  end
97
191
 
98
192
  test 'add ipinfo to record with custom out_key' do
99
- conf = %[
193
+ config = %[
100
194
  @type ipinfo
101
195
  out_key geodata
102
196
  ]
103
197
  messages = [
104
- { 'ip_address' => '8.8.8.8' }
198
+ {
199
+ 'ip_address' => '8.8.8.8'
200
+ }
105
201
  ]
106
202
  expected = [
107
- { 'ip_address' => '8.8.8.8',
203
+ {
204
+ 'ip_address' => '8.8.8.8',
108
205
  'geodata' => {
109
206
  'country_name' => 'United States',
110
207
  'region' => 'California',
@@ -114,62 +211,98 @@ class IPinfoFilterTest < Test::Unit::TestCase
114
211
  }
115
212
  }
116
213
  ]
117
- filtered_records = filter(conf, messages)
214
+ filtered_records = filter(config, messages)
215
+ assert_equal(expected, filtered_records)
216
+ end
217
+
218
+ test 'add ipinfo to record with custom out_key that is already defined' do
219
+ config = %[
220
+ @type ipinfo
221
+ out_key geodata
222
+ ]
223
+ messages = [
224
+ {
225
+ 'ip_address' => '8.8.8.8',
226
+ 'geodata' => 'bye!'
227
+ }
228
+ ]
229
+ expected = [
230
+ {
231
+ 'ip_address' => '8.8.8.8',
232
+ 'geodata' => {
233
+ 'country_name' => 'United States',
234
+ 'region' => 'California',
235
+ 'city' => 'Mountain View',
236
+ 'latitude' => '37.4056',
237
+ 'longitude' => '-122.0775'
238
+ }
239
+ }
240
+ ]
241
+ filtered_records = filter(config, messages)
118
242
  assert_equal(expected, filtered_records)
119
243
  end
120
244
 
121
245
  test 'add ipinfo to record with custom fields' do
122
- conf = %[
246
+ config = %[
123
247
  @type ipinfo
124
248
  fields ["country_name", "city"]
125
249
  ]
126
250
  messages = [
127
- { 'ip_address' => '8.8.8.8' }
251
+ {
252
+ 'ip_address' => '8.8.8.8'
253
+ }
128
254
  ]
129
255
  expected = [
130
- { 'ip_address' => '8.8.8.8',
256
+ {
257
+ 'ip_address' => '8.8.8.8',
131
258
  'ipinfo' => {
132
259
  'country_name' => 'United States',
133
260
  'city' => 'Mountain View'
134
261
  }
135
262
  }
136
263
  ]
137
- filtered_records = filter(conf, messages)
264
+ filtered_records = filter(config, messages)
138
265
  assert_equal(expected, filtered_records)
139
266
  end
140
267
 
141
268
  test 'add ipinfo to record with custom key_name and custom fields' do
142
- conf = %[
269
+ config = %[
143
270
  @type ipinfo
144
271
  key_name ip
145
272
  fields ["country_name", "city"]
146
273
  ]
147
274
  messages = [
148
- { 'ip' => '8.8.8.8' }
275
+ {
276
+ 'ip' => '8.8.8.8'
277
+ }
149
278
  ]
150
279
  expected = [
151
- { 'ip' => '8.8.8.8',
280
+ {
281
+ 'ip' => '8.8.8.8',
152
282
  'ipinfo' => {
153
283
  'country_name' => 'United States',
154
284
  'city' => 'Mountain View'
155
285
  }
156
286
  }
157
287
  ]
158
- filtered_records = filter(conf, messages)
288
+ filtered_records = filter(config, messages)
159
289
  assert_equal(expected, filtered_records)
160
290
  end
161
291
 
162
292
  test 'add ipinfo to record with custom key_name and custom out_key' do
163
- conf = %[
293
+ config = %[
164
294
  @type ipinfo
165
295
  key_name ip
166
296
  out_key geodata
167
297
  ]
168
298
  messages = [
169
- { 'ip' => '8.8.8.8' }
299
+ {
300
+ 'ip' => '8.8.8.8'
301
+ }
170
302
  ]
171
303
  expected = [
172
- { 'ip' => '8.8.8.8',
304
+ {
305
+ 'ip' => '8.8.8.8',
173
306
  'geodata' => {
174
307
  'country_name' => 'United States',
175
308
  'region' => 'California',
@@ -179,29 +312,32 @@ class IPinfoFilterTest < Test::Unit::TestCase
179
312
  }
180
313
  }
181
314
  ]
182
- filtered_records = filter(conf, messages)
315
+ filtered_records = filter(config, messages)
183
316
  assert_equal(expected, filtered_records)
184
317
  end
185
318
 
186
319
  test 'add ipinfo to record with custom key_name, custom out_name and custom fields' do
187
- conf = %[
320
+ config = %[
188
321
  @type ipinfo
189
322
  key_name ip
190
323
  out_key geodata
191
324
  fields ["country_name", "city"]
192
325
  ]
193
326
  messages = [
194
- { 'ip' => '8.8.8.8' }
327
+ {
328
+ 'ip' => '8.8.8.8'
329
+ }
195
330
  ]
196
331
  expected = [
197
- { 'ip' => '8.8.8.8',
332
+ {
333
+ 'ip' => '8.8.8.8',
198
334
  'geodata' => {
199
335
  'country_name' => 'United States',
200
336
  'city' => 'Mountain View'
201
337
  }
202
338
  }
203
339
  ]
204
- filtered_records = filter(conf, messages)
340
+ filtered_records = filter(config, messages)
205
341
  assert_equal(expected, filtered_records)
206
342
  end
207
343
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-ipinfo
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ahmed Abdelkafi