logstash-filter-dns 2.0.2 → 2.1.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 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: []