logstash-output-udp 3.0.6 → 3.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
  SHA256:
3
- metadata.gz: 03da8b46cdf2746435b5822fce43ac3310c990748e316c53e2d0068cf29a682c
4
- data.tar.gz: a50dae007a3c6db9c856acd7dd058b73765c21b04180a5ff6bc834000830f6a3
3
+ metadata.gz: f6d89de043149e0924a181b904dfd2d56766fd52c77ffb7ad623c27c3ee18df4
4
+ data.tar.gz: 94ad42d0d5b5d9c2bda8714318b3ca79899b8889e1db69e1e2a4c71358059f2d
5
5
  SHA512:
6
- metadata.gz: 7543ed4c366a4f9dde7916c560de384fb4991f337d4fc534c55690b242df85d10c8b559a7612924dcad746c4d2d770115b2a0b8d45bd10c7c4614e6bc9c23c0c
7
- data.tar.gz: 840f950c945e73a96de90afa3fd25f3b8e2b2df3ac204b576bbb1b2ab7458e2ddd264b3b815b968ff1724ec170461763d58362c3f86766984553a3b59dacb792
6
+ metadata.gz: ead3de8b14b596c8cac1330ca63737232fb8d8ce5e2564f5aed6cedb54e811662dae7ba2a2a36680ba6aba9d11aa1ce6f14e1e35888076d01907de6976fb5e2d
7
+ data.tar.gz: 71d2903845ceed02477768fe9eea5ca8c27a0875ba064b96a2d396331c726d1bbaa0aca88d64ed9df77b70a7ab30b0523ceaf67a648436f87449a33ba4b9cf26
@@ -1,3 +1,7 @@
1
+ ## 3.1.0
2
+ - Fixed plugin crash upon socket write exception [#10](https://github.com/logstash-plugins/logstash-output-udp/pull/10)
3
+ - Added support for the 'retry_count' and 'retry_backoff_ms' options [#12](https://github.com/logstash-plugins/logstash-output-udp/pull/12)
4
+
1
5
  ## 3.0.6
2
6
  - Docs: Set the default_codec doc attribute.
3
7
 
@@ -23,7 +23,14 @@ include::{include_path}/plugin_header.asciidoc[]
23
23
 
24
24
  Send events over UDP
25
25
 
26
- Keep in mind that UDP will lose messages.
26
+ Keep in mind that UDP does not provide delivery or duplicate protection guarantees.
27
+ Even when this plugin succeeds at writing to the UDP socket, there is no guarantee that
28
+ the recipient will receive exactly one copy of the event.
29
+
30
+ When this plugin fails to write to the UDP socket, by default the event will be dropped
31
+ and the error message will be logged. The <<plugins-{type}s-{plugin}-retry_count>> option
32
+ in conjunction with the <<plugins-{type}s-{plugin}-retry_backoff_ms>> option can be used
33
+ to retry a failed write for a number of times before dropping the event.
27
34
 
28
35
  [id="plugins-{type}s-{plugin}-options"]
29
36
  ==== Udp Output Configuration Options
@@ -35,6 +42,8 @@ This plugin supports the following configuration options plus the <<plugins-{typ
35
42
  |Setting |Input type|Required
36
43
  | <<plugins-{type}s-{plugin}-host>> |<<string,string>>|Yes
37
44
  | <<plugins-{type}s-{plugin}-port>> |<<number,number>>|Yes
45
+ | <<plugins-{type}s-{plugin}-retry_count>> |<<number,number>>|No
46
+ | <<plugins-{type}s-{plugin}-retry_backoff_ms>> |<<number,number>>|No
38
47
  |=======================================================================
39
48
 
40
49
  Also see <<plugins-{type}s-{plugin}-common-options>> for a list of options supported by all
@@ -60,7 +69,21 @@ The address to send messages to
60
69
 
61
70
  The port to send messages on
62
71
 
72
+ [id="plugins-{type}s-{plugin}-retry_count"]
73
+ ===== `retry_count`
74
+
75
+ * Value type is <<number,number>>
76
+ * Default value is `0`
77
+
78
+ The number of times to retry a failed UPD socket write
79
+
80
+ [id="plugins-{type}s-{plugin}-retry_backoff_ms"]
81
+ ===== `retry_backoff_ms`
82
+
83
+ * Value type is <<number,number>>
84
+ * Default value is `10`
63
85
 
86
+ The amount of time to wait in milliseconds before attempting to retry a failed UPD socket write
64
87
 
65
88
  [id="plugins-{type}s-{plugin}-common-options"]
66
89
  include::{include_path}/{type}.asciidoc[]
@@ -5,7 +5,7 @@ require "socket"
5
5
 
6
6
  # Send events over UDP
7
7
  #
8
- # Keep in mind that UDP will lose messages.
8
+ # Keep in mind that UDP is a lossy protocol
9
9
  class LogStash::Outputs::UDP < LogStash::Outputs::Base
10
10
  config_name "udp"
11
11
 
@@ -17,18 +17,58 @@ class LogStash::Outputs::UDP < LogStash::Outputs::Base
17
17
  # The port to send messages on
18
18
  config :port, :validate => :number, :required => true
19
19
 
20
- public
20
+ # The number of times to retry a failed UPD socket write
21
+ config :retry_count, :validate => :number, :default => 0
22
+
23
+ # The amount of time to wait in milliseconds before attempting to retry a failed UPD socket write
24
+ config :retry_backoff_ms, :validate => :number, :default => 100
25
+
21
26
  def register
22
27
  @socket = UDPSocket.new
28
+
23
29
  @codec.on_event do |event, payload|
24
- @socket.send(payload, 0, @host, @port)
30
+ socket_send(payload)
25
31
  end
26
32
  end
27
33
 
28
34
  def receive(event)
29
-
30
- return if event == LogStash::SHUTDOWN
31
35
  @codec.encode(event)
32
36
  end
33
37
 
34
- end # class LogStash::Outputs::Stdout
38
+ private
39
+
40
+ def socket_send(payload)
41
+ send_count = 0
42
+ begin
43
+ send_count += 1
44
+ @socket.send(payload, 0, @host, @port)
45
+ rescue Errno::EMSGSIZE => e
46
+ logger.error("Failed to send event, message size of #{payload.size} too long", error_hash(e, payload))
47
+ rescue => e
48
+ if @retry_count > 0 && send_count <= @retry_count
49
+ logger.warn("Failed to send event, retrying:", error_hash(e, payload))
50
+ sleep(@retry_backoff_ms / 1000.0)
51
+ retry
52
+ else
53
+ logger.error("Failed to send event:", error_hash(e, payload))
54
+ end
55
+ end
56
+ end
57
+
58
+ MAX_DEBUG_PAYLOAD = 1000
59
+
60
+ def error_hash(error, payload)
61
+ error_hash = {
62
+ :error => error.inspect,
63
+ :backtrace => error.backtrace.first(10)
64
+ }
65
+ if logger.debug?
66
+ error_hash.merge(
67
+ :event_payload =>
68
+ payload.length > MAX_DEBUG_PAYLOAD ? "#{payload[0...MAX_DEBUG_PAYLOAD]}...<TRUNCATED>" : payload
69
+ )
70
+ else
71
+ error_hash
72
+ end
73
+ end
74
+ end
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
 
3
3
  s.name = 'logstash-output-udp'
4
- s.version = '3.0.6'
4
+ s.version = '3.1.0'
5
5
  s.licenses = ['Apache License (2.0)']
6
6
  s.summary = "Sends events over UDP"
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/logstash-plugin install gemname. This gem is not a stand-alone program"
@@ -3,18 +3,17 @@ require_relative "../spec_helper"
3
3
 
4
4
  describe LogStash::Outputs::UDP do
5
5
 
6
+ subject { described_class.new(config) }
6
7
  let(:host) { "localhost" }
7
8
  let(:port) { rand(1024..65535) }
9
+ let(:config) {{ "host" => host, "port" => port}}
8
10
 
9
11
  it "should register without errors" do
10
- plugin = LogStash::Plugin.lookup("output", "udp").new({ "host" => host, "port" => port})
12
+ plugin = LogStash::Plugin.lookup("output", "udp").new(config)
11
13
  expect { plugin.register }.to_not raise_error
12
14
  end
13
15
 
14
16
  describe "#send" do
15
-
16
- subject { LogStash::Outputs::UDP.new({"host" => host, "port" => port}) }
17
-
18
17
  let(:properties) { { "message" => "This is a message!"} }
19
18
  let(:event) { LogStash::Event.new(properties) }
20
19
 
@@ -24,7 +23,71 @@ describe LogStash::Outputs::UDP do
24
23
 
25
24
  it "should receive the generated event" do
26
25
  expect(subject.instance_variable_get("@socket")).to receive(:send).with(kind_of(String), 0, host, port)
26
+ expect(subject.instance_variable_get("@logger")).not_to receive(:error)
27
+ subject.receive(event)
28
+ end
29
+ end
30
+
31
+ describe "retries" do
32
+ let(:event) { LogStash::Event.new("message" => "test") }
33
+ let(:config) {{ "host" => host, "port" => port}}
34
+
35
+ before(:each) do
36
+ subject.register
37
+ end
38
+
39
+ context "not using :retry_count" do
40
+ it "should not retry upon send exception by default" do
41
+ allow(subject.instance_variable_get("@socket")).to receive(:send).once.and_raise(IOError)
42
+ expect(subject.instance_variable_get("@logger")).to receive(:error).once
43
+ subject.receive(event)
44
+ end
45
+ end
46
+
47
+ context "using :retry_count" do
48
+ let(:backoff) { 10 }
49
+ let(:retry_count) { 5 }
50
+ let(:config) {{ "host" => host, "port" => port, "retry_count" => retry_count, "retry_backoff_ms" => backoff}}
51
+
52
+ it "should retry upon send exception" do
53
+ allow(subject.instance_variable_get("@socket")).to receive(:send).exactly(retry_count + 1).times.and_raise(IOError)
54
+ expect(subject.instance_variable_get("@logger")).to receive(:warn).exactly(retry_count).times
55
+ expect(subject.instance_variable_get("@logger")).to receive(:error).once
56
+ expect(subject).to receive(:sleep).with(backoff / 1000.0).exactly(retry_count).times
57
+ subject.receive(event)
58
+ end
59
+ end
60
+ end
61
+
62
+ describe "large message" do
63
+ let(:properties) { { "message" => "0" * 65_536 } }
64
+ let(:event) { LogStash::Event.new(properties) }
65
+
66
+ before(:each) do
67
+ subject.register
68
+ end
69
+
70
+ it "should handle the error and log when an error is received" do
71
+ expect(subject.instance_variable_get("@logger")).to receive(:error)
27
72
  subject.receive(event)
28
73
  end
74
+
75
+ it "should log a truncated payload with debug logging when an error is received and the message is too long" do
76
+ expect(subject.instance_variable_get("@logger")).to receive(:debug?).and_return(true)
77
+ expect(subject.instance_variable_get("@logger")).to receive(:error) do |_, hash|
78
+ expect(hash).to include(:event_payload)
79
+ expect(hash[:event_payload]).to include("TRUNCATED")
80
+ end
81
+ subject.receive(event)
82
+ end
83
+
84
+ it "should not log a payload with debug logging when an error is received" do
85
+ expect(subject.instance_variable_get("@logger")).to receive(:debug?).and_return(false)
86
+ expect(subject.instance_variable_get("@logger")).to receive(:error) do |_, hash|
87
+ expect(hash).not_to include(:event_payload)
88
+ end
89
+ subject.receive(event)
90
+ end
91
+
29
92
  end
30
93
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstash-output-udp
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.6
4
+ version: 3.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: 2018-04-06 00:00:00.000000000 Z
11
+ date: 2019-12-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -99,7 +99,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
99
99
  version: '0'
100
100
  requirements: []
101
101
  rubyforge_project:
102
- rubygems_version: 2.6.11
102
+ rubygems_version: 2.6.13
103
103
  signing_key:
104
104
  specification_version: 4
105
105
  summary: Sends events over UDP