logstash-filter-dns 2.0.2 → 2.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
  SHA1:
3
- metadata.gz: e19a68ccd4a4f4f02f625a725e18ad3c74f5eda3
4
- data.tar.gz: 5cabe33a4eed9ee6dcf594ae75c8eb3831607386
3
+ metadata.gz: 4665d1daf1b87421818c9e6bd11f6efadb74349c
4
+ data.tar.gz: 4dcb49b8c0e902156fa2ebc3aadd9e97e3b7252f
5
5
  SHA512:
6
- metadata.gz: 525124b0bd2e5cd58a0637534bf2d9902b1f0b6b7fbaa1d12acd434346d38fc0166748dcc87ec081a524ec2ec245c91077995c19ba5d424538b36dd3d97adec2
7
- data.tar.gz: de90a47925204eb2cd4d4bb9e3084a2606dee71d690238b5044f79986359545979e60e19c0e3694698fb9ba8973ccd64f0cf25dacce51f5c06dfc9382a06266a
6
+ metadata.gz: 87b081e655bd9eb3e2a939cea5a1464328e7225ac655f30ae4fc4a8702b026715bf15576d642baeea467d9801272980f9555c669f5cfbd928e9a3b0abd1d3c13
7
+ data.tar.gz: 3d18bbc3ae5ae1661763334793b199fea6a07405e2b869ad19614906f1c06ca9382ae7014d0fbb74bbc47f8c380f955b52e6b08b52a5bc7490217e812a895b04
@@ -1,3 +1,8 @@
1
+ ## 2.1.0
2
+ - Add caches for failed and successful lookups
3
+ - Lower default timeout value
4
+ - Retry a maximum of :max_retries instead of failing immediately
5
+
1
6
  ## 2.0.0
2
7
  - Plugins were updated to follow the new shutdown semantic, this mainly allows Logstash to instruct input plugins to terminate gracefully,
3
8
  instead of using Thread.raise on the plugins' threads. Ref: https://github.com/elastic/logstash/pull/3895
data/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # Logstash Plugin
2
2
 
3
+ [![Build
4
+ Status](http://build-eu-00.elastic.co/view/LS%20Plugins/view/LS%20Filters/job/logstash-plugin-filter-dns-unit/badge/icon)](http://build-eu-00.elastic.co/view/LS%20Plugins/view/LS%20Filters/job/logstash-plugin-filter-dns-unit/)
5
+
3
6
  This is a plugin for [Logstash](https://github.com/elastic/logstash).
4
7
 
5
8
  It is fully free and fully open source. The license is Apache 2.0, meaning you are pretty much free to use it however you want in whatever way.
@@ -1,6 +1,8 @@
1
1
  # encoding: utf-8
2
2
  require "logstash/filters/base"
3
3
  require "logstash/namespace"
4
+ require "lru_redux"
5
+
4
6
 
5
7
  # The DNS filter performs a lookup (either an A record/CNAME record lookup
6
8
  # or a reverse lookup at the PTR record) on records specified under the
@@ -18,7 +20,7 @@ require "logstash/namespace"
18
20
  # }
19
21
  #
20
22
  # Caveats: Currently there is no way to specify a timeout in the DNS lookup.
21
- #
23
+ #
22
24
  # This filter, like all filters, only processes 1 event at a time, so the use
23
25
  # of this plugin can significantly slow down your pipeline's throughput if you
24
26
  # have a high latency network. By way of example, if each DNS lookup takes 2
@@ -46,7 +48,22 @@ class LogStash::Filters::DNS < LogStash::Filters::Base
46
48
  config :nameserver, :validate => :array
47
49
 
48
50
  # `resolv` calls will be wrapped in a timeout instance
49
- config :timeout, :validate => :number, :default => 2
51
+ config :timeout, :validate => :number, :default => 0.5
52
+
53
+ # number of times to retry a failed resolve/reverse
54
+ config :max_retries, :validate => :number, :default => 2
55
+
56
+ # set the size of cache for successful requests
57
+ config :hit_cache_size, :validate => :number, :default => 0
58
+
59
+ # how long to cache successful requests (in seconds)
60
+ config :hit_cache_ttl, :validate => :number, :default => 60
61
+
62
+ # cache size for failed requests (Resolv::
63
+ config :failed_cache_size, :validate => :number, :default => 0
64
+
65
+ # how long to cache failed requests (in seconds)
66
+ config :failed_cache_ttl, :validate => :number, :default => 5
50
67
 
51
68
  public
52
69
  def register
@@ -58,42 +75,29 @@ class LogStash::Filters::DNS < LogStash::Filters::Base
58
75
  @resolv = Resolv.new(resolvers=[::Resolv::Hosts.new, ::Resolv::DNS.new(:nameserver => @nameserver, :search => [], :ndots => 1)])
59
76
  end
60
77
 
78
+ if @hit_cache_size > 0
79
+ @hit_cache = LruRedux::ThreadSafeCache.new(@hit_cache_size, @hit_cache_ttl)
80
+ end
81
+
82
+ if @failed_cache_size > 0
83
+ @failed_cache = LruRedux::ThreadSafeCache.new(@failed_cache_size, @failed_cache_ttl)
84
+ end
85
+
61
86
  @ip_validator = Resolv::AddressRegex
62
87
  end # def register
63
88
 
64
89
  public
65
90
  def filter(event)
66
-
67
-
68
- new_event = event.clone
69
91
 
70
92
  if @resolve
71
- begin
72
- status = Timeout::timeout(@timeout) {
73
- resolve(new_event)
74
- }
75
- return if status.nil?
76
- rescue Timeout::Error
77
- @logger.debug("DNS: resolve action timed out")
78
- return
79
- end
93
+ return if resolve(event).nil?
80
94
  end
81
95
 
82
96
  if @reverse
83
- begin
84
- status = Timeout::timeout(@timeout) {
85
- reverse(new_event)
86
- }
87
- return if status.nil?
88
- rescue Timeout::Error
89
- @logger.debug("DNS: reverse action timed out")
90
- return
91
- end
97
+ return if reverse(event).nil?
92
98
  end
93
99
 
94
- filter_matched(new_event)
95
- yield new_event
96
- event.cancel
100
+ filter_matched(event)
97
101
  end
98
102
 
99
103
  private
@@ -111,25 +115,24 @@ class LogStash::Filters::DNS < LogStash::Filters::Base
111
115
  end
112
116
 
113
117
  begin
114
- # in JRuby 1.7.11 outputs as US-ASCII
115
- address = @resolv.getaddress(raw).force_encoding(Encoding::UTF_8)
118
+ return if @failed_cache && @failed_cache[raw] # recently failed resolv, skip
119
+ if @hit_cache
120
+ address = @hit_cache.getset(raw) { retriable_getaddress(raw) }
121
+ else
122
+ address = retriable_getaddress(raw)
123
+ end
116
124
  rescue Resolv::ResolvError
125
+ @failed_cache[raw] = true if @failed_cache
117
126
  @logger.debug("DNS: couldn't resolve the hostname.",
118
127
  :field => field, :value => raw)
119
128
  return
120
- rescue Resolv::ResolvTimeout
121
- @logger.debug("DNS: timeout on resolving the hostname.",
129
+ rescue Resolv::ResolvTimeout, Timeout::Error
130
+ @logger.error("DNS: timeout on resolving the hostname.",
122
131
  :field => field, :value => raw)
123
132
  return
124
133
  rescue SocketError => e
125
- @logger.debug("DNS: Encountered SocketError.",
126
- :field => field, :value => raw)
127
- return
128
- rescue NoMethodError => e
129
- # see JRUBY-5647
130
- @logger.debug("DNS: couldn't resolve the hostname.",
131
- :field => field, :value => raw,
132
- :extra => "NameError instead of ResolvError")
134
+ @logger.error("DNS: Encountered SocketError.",
135
+ :field => field, :value => raw, :message => e.message)
133
136
  return
134
137
  end
135
138
 
@@ -170,19 +173,24 @@ class LogStash::Filters::DNS < LogStash::Filters::Base
170
173
  return
171
174
  end
172
175
  begin
173
- # in JRuby 1.7.11 outputs as US-ASCII
174
- hostname = @resolv.getname(raw).force_encoding(Encoding::UTF_8)
176
+ return if @failed_cache && @failed_cache.key?(raw) # recently failed resolv, skip
177
+ if @hit_cache
178
+ hostname = @hit_cache.getset(raw) { retriable_getname(raw) }
179
+ else
180
+ hostname = retriable_getname(raw)
181
+ end
175
182
  rescue Resolv::ResolvError
183
+ @failed_cache[raw] = true if @failed_cache
176
184
  @logger.debug("DNS: couldn't resolve the address.",
177
185
  :field => field, :value => raw)
178
186
  return
179
- rescue Resolv::ResolvTimeout
180
- @logger.debug("DNS: timeout on resolving address.",
187
+ rescue Resolv::ResolvTimeout, Timeout::Error
188
+ @logger.error("DNS: timeout on resolving address.",
181
189
  :field => field, :value => raw)
182
190
  return
183
191
  rescue SocketError => e
184
- @logger.debug("DNS: Encountered SocketError.",
185
- :field => field, :value => raw)
192
+ @logger.error("DNS: Encountered SocketError.",
193
+ :field => field, :value => raw, :message => e.message)
186
194
  return
187
195
  end
188
196
 
@@ -201,4 +209,45 @@ class LogStash::Filters::DNS < LogStash::Filters::Base
201
209
  end
202
210
  end
203
211
  end
212
+
213
+ private
214
+ def retriable_request(&block)
215
+ tries = 0
216
+ begin
217
+ Timeout::timeout(@timeout) do
218
+ block.call
219
+ end
220
+ rescue Timeout::Error, SocketError
221
+ if tries < @max_retries
222
+ tries = tries + 1
223
+ retry
224
+ else
225
+ raise
226
+ end
227
+ end
228
+ end
229
+
230
+ private
231
+ def retriable_getname(address)
232
+ retriable_request do
233
+ getname(address)
234
+ end
235
+ end
236
+
237
+ private
238
+ def retriable_getaddress(name)
239
+ retriable_request do
240
+ getaddress(name)
241
+ end
242
+ end
243
+
244
+ private
245
+ def getname(address)
246
+ @resolv.getname(address).force_encoding(Encoding::UTF_8)
247
+ end
248
+
249
+ private
250
+ def getaddress(name)
251
+ @resolv.getaddress(name).force_encoding(Encoding::UTF_8)
252
+ end
204
253
  end # class LogStash::Filters::DNS
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
 
3
3
  s.name = 'logstash-filter-dns'
4
- s.version = '2.0.2'
4
+ s.version = '2.1.0'
5
5
  s.licenses = ['Apache License (2.0)']
6
6
  s.summary = "This filter will resolve any IP addresses from a field of your choosing."
7
7
  s.description = "This gem is a logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/plugin install gemname. This gem is not a stand-alone program"
@@ -21,6 +21,7 @@ Gem::Specification.new do |s|
21
21
 
22
22
  # Gem dependencies
23
23
  s.add_runtime_dependency "logstash-core", ">= 2.0.0.beta2", "< 3.0.0"
24
+ s.add_runtime_dependency 'lru_redux', "~> 1.1.0"
24
25
 
25
26
  s.add_development_dependency 'logstash-devutils'
26
27
  end
@@ -89,7 +89,7 @@ describe LogStash::Filters::DNS do
89
89
 
90
90
  sample("host1" => "carrera.databits.net", "host2" => "nonexistanthostname###.net") do
91
91
  insist { subject["tags"] }.nil?
92
- insist { subject["host1"] } == "carrera.databits.net"
92
+ insist { subject["host1"] } == "199.192.228.250"
93
93
  insist { subject["host2"] } == "nonexistanthostname###.net"
94
94
  end
95
95
  end
@@ -126,8 +126,8 @@ describe LogStash::Filters::DNS do
126
126
  "ip1" => "127.0.0.1",
127
127
  "ip2" => "128.0.0.1") do
128
128
  insist { subject["tags"] }.nil?
129
- insist { subject["host1"] } == "carrera.databits.net"
130
- insist { subject["ip1"] } == "127.0.0.1"
129
+ insist { subject["host1"] } == "199.192.228.250"
130
+ insist { subject["ip1"] } == "localhost"
131
131
  insist { subject["ip2"] } == "128.0.0.1"
132
132
  end
133
133
  end
@@ -238,4 +238,124 @@ describe LogStash::Filters::DNS do
238
238
  insist { subject["host"] } == "199.192.228.250"
239
239
  end
240
240
  end
241
+
242
+ describe "dns resolve lookup, multiple nameserver fallback" do
243
+ config <<-CONFIG
244
+ filter {
245
+ dns {
246
+ resolve => ["host"]
247
+ action => "replace"
248
+ nameserver => ["127.0.0.99", "8.8.8.8"]
249
+ }
250
+ }
251
+ CONFIG
252
+
253
+ sample("host" => "carrera.databits.net") do
254
+ insist { subject["host"] } == "199.192.228.250"
255
+ end
256
+ end
257
+
258
+ describe "failed cache" do
259
+
260
+ let(:subject) { LogStash::Filters::DNS.new(config) }
261
+ let(:event1) { LogStash::Event.new("message" => "unkownhost") }
262
+ let(:event2) { LogStash::Event.new("message" => "unkownhost") }
263
+
264
+ before(:each) do
265
+ allow(subject).to receive(:getaddress).and_raise Resolv::ResolvError
266
+ subject.register
267
+ end
268
+
269
+ context "when enabled" do
270
+ let(:config) { { "resolve" => ["message"], "failed_cache_size" => 3 } }
271
+
272
+ it "should cache a failed lookup" do
273
+ expect(subject).to receive(:getaddress).once
274
+ subject.filter(event1)
275
+ subject.filter(event2)
276
+ end
277
+ end
278
+
279
+ context "when disabled" do
280
+ let(:config) { { "resolve" => ["message"] } }
281
+
282
+ it "should not cache a failed lookup" do
283
+ expect(subject).to receive(:getaddress).twice
284
+ subject.filter(event1)
285
+ subject.filter(event2)
286
+ end
287
+ end
288
+ end
289
+
290
+ describe "hit cache" do
291
+
292
+ let(:subject) { LogStash::Filters::DNS.new(config) }
293
+ let(:event1) { LogStash::Event.new("message" => "unkownhost") }
294
+ let(:event2) { LogStash::Event.new("message" => "unkownhost") }
295
+
296
+ before(:each) do
297
+ allow(subject).to receive(:getaddress).and_return("127.0.0.1")
298
+ subject.register
299
+ end
300
+
301
+ context "when enabled" do
302
+ let(:config) { { "resolve" => ["message"], "hit_cache_size" => 3 } }
303
+
304
+ it "should cache a succesful lookup" do
305
+ expect(subject).to receive(:getaddress).once
306
+ subject.filter(event1)
307
+ subject.filter(event2)
308
+ end
309
+ end
310
+
311
+ context "when disabled" do
312
+ let(:config) { { "resolve" => ["message"] } }
313
+
314
+ it "should not cache a successful lookup" do
315
+ expect(subject).to receive(:getaddress).twice
316
+ subject.filter(event1)
317
+ subject.filter(event2)
318
+ end
319
+ end
320
+ end
321
+
322
+ describe "retries" do
323
+
324
+ let(:subject) { LogStash::Filters::DNS.new(config) }
325
+ let(:event) { LogStash::Event.new("message" => "unkownhost") }
326
+ let(:max_retries) { 3 }
327
+ let(:config) { { "resolve" => ["message"], "max_retries" => max_retries } }
328
+
329
+ before(:each) { subject.register }
330
+
331
+ context "when failing permanently" do
332
+ before(:each) do
333
+ allow(subject).to receive(:getaddress).and_raise(Timeout::Error)
334
+ end
335
+
336
+ it "should fail a resolve after max_retries" do
337
+ expect(subject).to receive(:getaddress).exactly(max_retries+1).times
338
+ subject.filter(event)
339
+ end
340
+ end
341
+
342
+ context "when failing temporarily" do
343
+ before(:each) do
344
+ allow(subject).to receive(:getaddress) do
345
+ @try ||= 0
346
+ if @try < 3
347
+ @try = @try + 1
348
+ raise Timeout::Error
349
+ else
350
+ return "127.0.0.1"
351
+ end
352
+ end
353
+ end
354
+
355
+ it "should resolve before max_retries" do
356
+ expect(subject).to receive(:getaddress).exactly(3).times
357
+ subject.filter(event)
358
+ end
359
+ end
360
+ end
241
361
  end
metadata CHANGED
@@ -1,17 +1,18 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstash-filter-dns
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.2
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Elastic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-10-14 00:00:00.000000000 Z
11
+ date: 2016-02-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- requirement: !ruby/object:Gem::Requirement
14
+ name: logstash-core
15
+ version_requirements: !ruby/object:Gem::Requirement
15
16
  requirements:
16
17
  - - '>='
17
18
  - !ruby/object:Gem::Version
@@ -19,10 +20,7 @@ dependencies:
19
20
  - - <
20
21
  - !ruby/object:Gem::Version
21
22
  version: 3.0.0
22
- name: logstash-core
23
- prerelease: false
24
- type: :runtime
25
- version_requirements: !ruby/object:Gem::Requirement
23
+ requirement: !ruby/object:Gem::Requirement
26
24
  requirements:
27
25
  - - '>='
28
26
  - !ruby/object:Gem::Version
@@ -30,20 +28,36 @@ dependencies:
30
28
  - - <
31
29
  - !ruby/object:Gem::Version
32
30
  version: 3.0.0
31
+ prerelease: false
32
+ type: :runtime
33
33
  - !ruby/object:Gem::Dependency
34
+ name: lru_redux
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ~>
38
+ - !ruby/object:Gem::Version
39
+ version: 1.1.0
34
40
  requirement: !ruby/object:Gem::Requirement
35
41
  requirements:
36
- - - '>='
42
+ - - ~>
37
43
  - !ruby/object:Gem::Version
38
- version: '0'
39
- name: logstash-devutils
44
+ version: 1.1.0
40
45
  prerelease: false
41
- type: :development
46
+ type: :runtime
47
+ - !ruby/object:Gem::Dependency
48
+ name: logstash-devutils
42
49
  version_requirements: !ruby/object:Gem::Requirement
43
50
  requirements:
44
51
  - - '>='
45
52
  - !ruby/object:Gem::Version
46
53
  version: '0'
54
+ requirement: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - '>='
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ prerelease: false
60
+ type: :development
47
61
  description: This gem is a logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/plugin install gemname. This gem is not a stand-alone program
48
62
  email: info@elastic.co
49
63
  executables: []