Skip to content

Commit c5e7637

Browse files
committed
backport client-closing and logging standardization from 6.1.0
1 parent 2f73981 commit c5e7637

File tree

2 files changed

+55
-14
lines changed

2 files changed

+55
-14
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 6.0.3
2+
- Pulled applicable back-ports from 6.1.0
3+
- Fix: Ensure sockets are closed when this plugin is closed
4+
15
## 6.0.2
26
- Fix: unable to start with password protected key [#45](https://github.com/logstash-plugins/logstash-output-tcp/pull/45)
37

lib/logstash/outputs/tcp.rb

+51-14
Original file line numberDiff line numberDiff line change
@@ -51,31 +51,36 @@ class LogStash::Outputs::Tcp < LogStash::Outputs::Base
5151
# SSL key passphrase
5252
config :ssl_key_passphrase, :validate => :password, :default => nil
5353

54+
##
55+
# @param socket [Socket]
56+
# @param logger_context [#log_warn&#log_error]
5457
class Client
55-
public
56-
def initialize(socket, logger)
58+
def initialize(socket, logger_context)
5759
@socket = socket
58-
@logger = logger
60+
@logger_context = logger_context
5961
@queue = Queue.new
6062
end
6163

62-
public
6364
def run
6465
loop do
6566
begin
6667
@socket.write(@queue.pop)
6768
rescue => e
68-
@logger.warn("tcp output exception", :socket => @socket,
69-
:exception => e)
69+
@logger_context.log_warn("tcp output exception: socket write failed", e, :socket => @socket&.to_s)
7070
break
7171
end
7272
end
7373
end # def run
7474

75-
public
7675
def write(msg)
7776
@queue.push(msg)
7877
end # def write
78+
79+
def close
80+
@socket.close
81+
rescue => e
82+
@logger_context.log_warn 'socket close failed:', e, socket: @socket&.to_s)
83+
end
7984
end # class Client
8085

8186
private
@@ -113,6 +118,8 @@ def register
113118
if @ssl_enable
114119
setup_ssl
115120
end # @ssl_enable
121+
@closed = Concurrent::AtomicBoolean.new(false)
122+
@thread_no = Concurrent::AtomicFixnum.new(0)
116123

117124
if server?
118125
@logger.info("Starting tcp output listener", :address => "#{@host}:#{@port}")
@@ -129,25 +136,28 @@ def register
129136
@client_threads = []
130137

131138
@accept_thread = Thread.new(@server_socket) do |server_socket|
139+
LogStash::Util.set_thread_name("[#{pipeline_id}]|output|tcp|server_accept")
132140
loop do
141+
break if @closed.value
133142
Thread.start(server_socket.accept) do |client_socket|
134143
# monkeypatch a 'peer' method onto the socket.
135144
client_socket.instance_eval { class << self; include ::LogStash::Util::SocketPeer end }
136145
@logger.debug("Accepted connection", :client => client_socket.peer,
137146
:server => "#{@host}:#{@port}")
138-
client = Client.new(client_socket, @logger)
147+
client = Client.new(client_socket, self)
139148
Thread.current[:client] = client
149+
LogStash::Util.set_thread_name("[#{pipeline_id}]|output|tcp|client_socket-#{@thread_no.increment}")
140150
@client_threads << Thread.current
141-
client.run
151+
client.run unless @closed.value
142152
end
143153
end
144154
end
145155

146156
@codec.on_event do |event, payload|
157+
@client_threads.select!(&:alive?)
147158
@client_threads.each do |client_thread|
148159
client_thread[:client].write(payload)
149160
end
150-
@client_threads.reject! {|t| !t.alive? }
151161
end
152162
else
153163
client_socket = nil
@@ -163,8 +173,7 @@ def register
163173
# Now send the payload
164174
client_socket.syswrite(payload) if w.any?
165175
rescue => e
166-
@logger.warn("tcp output exception", :host => @host, :port => @port,
167-
:exception => e, :backtrace => e.backtrace)
176+
log_warn "client socket failed:", e, host: @host, port: @port, socket: client_socket&.to_s
168177
client_socket.close rescue nil
169178
client_socket = nil
170179
sleep @reconnect_interval
@@ -174,6 +183,18 @@ def register
174183
end
175184
end # def register
176185

186+
# @overload Base#close
187+
def close
188+
@closed.make_true
189+
@server_socket.close rescue nil if @server_socket
190+
191+
return unless @client_threads
192+
@client_threads.each do |thread|
193+
client = thread[:client]
194+
client.close rescue nil if client
195+
end
196+
end
197+
177198
private
178199
def connect
179200
begin
@@ -183,7 +204,7 @@ def connect
183204
begin
184205
client_socket.connect
185206
rescue OpenSSL::SSL::SSLError => ssle
186-
@logger.error("SSL Error", :exception => ssle, :backtrace => ssle.backtrace)
207+
log_error 'connect ssl failure:', ssle, backtrace: false
187208
# NOTE(mrichar1): Hack to prevent hammering peer
188209
sleep(5)
189210
raise
@@ -193,7 +214,7 @@ def connect
193214
@logger.debug("Opened connection", :client => "#{client_socket.peer}")
194215
return client_socket
195216
rescue StandardError => e
196-
@logger.error("Failed to connect: #{e.message}", :exception => e.class, :backtrace => e.backtrace)
217+
log_error 'failed to connect:', e
197218
sleep @reconnect_interval
198219
retry
199220
end
@@ -208,4 +229,20 @@ def server?
208229
def receive(event)
209230
@codec.encode(event)
210231
end # def receive
232+
233+
def pipeline_id
234+
execution_context.pipeline_id || 'main'
235+
end
236+
237+
def log_warn(msg, e, backtrace: @logger.debug?, **details)
238+
details = details.merge message: e.message, exception: e.class
239+
details[:backtrace] = e.backtrace if backtrace
240+
@logger.warn(msg, details)
241+
end
242+
243+
def log_error(msg, e, backtrace: @logger.info?, **details)
244+
details = details.merge message: e.message, exception: e.class
245+
details[:backtrace] = e.backtrace if backtrace
246+
@logger.error(msg, details)
247+
end
211248
end # class LogStash::Outputs::Tcp

0 commit comments

Comments
 (0)