From aa7d3eff10e70905647fa5c1c6e24ed0e03a4717 Mon Sep 17 00:00:00 2001 From: Shizuo Fujita Date: Tue, 8 Jul 2025 11:59:29 +0900 Subject: [PATCH 1/7] Add connect_timeout / resolve_timeout option Signed-off-by: Shizuo Fujita --- README.md | 8 ++++++++ fluent-logger.gemspec | 2 ++ lib/fluent/logger/fluent_logger.rb | 5 ++++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3fa00fd..e22a48f 100644 --- a/README.md +++ b/README.md @@ -148,6 +148,14 @@ Use nonblocking write(`IO#write_nonblock`) instead of normal write(`IO#write`). If `false`, `Logger#post` raises an error when nonblocking write gets `EAGAIN` (i.e. `use_nonblock` must be `true`, otherwise this will have no effect). Default: `true` +#### connect_timeout (Integer) + +Specify timeout in seconds from connecting. Default: `nil` + +#### resolve_timeout (Integer) + +Specify timeout in seconds from when the hostname resolution starts. Default: `nil` + #### buffer_overflow_handler (Proc) Pass callback for handling buffer overflow with pending data. See "Buffer overflow" section. diff --git a/fluent-logger.gemspec b/fluent-logger.gemspec index 8811ae6..d8b4e1d 100644 --- a/fluent-logger.gemspec +++ b/fluent-logger.gemspec @@ -21,6 +21,8 @@ Gem::Specification.new do |gem| gem.require_paths = ['lib'] gem.license = "Apache-2.0" + gem.required_ruby_version = '>= 2.7' + gem.add_dependency "msgpack", ">= 1.0.0", "< 2" # logger gem that isn't default gems as of Ruby 3.5 diff --git a/lib/fluent/logger/fluent_logger.rb b/lib/fluent/logger/fluent_logger.rb index 0afec88..baa7375 100644 --- a/lib/fluent/logger/fluent_logger.rb +++ b/lib/fluent/logger/fluent_logger.rb @@ -115,6 +115,9 @@ def initialize(tag_prefix = nil, *args) @wait_writeable = true @wait_writeable = options[:wait_writeable] if options.key?(:wait_writeable) + @connect_timeout = options[:connect_timeout] + @resolv_timeout = options[:resolv_timeout] + @last_error = {} begin @@ -170,7 +173,7 @@ def create_socket! if @socket_path @con = UNIXSocket.new(@socket_path) else - @con = TCPSocket.new(@host, @port) + @con = Socket.tcp(@host, @port, connect_timeout: @connect_timeout, resolv_timeout: @resolv_timeout) if @tls_options context = OpenSSL::SSL::SSLContext.new if @tls_options[:insecure] From 5faccbe3618914a8669b7d7313b0b8668594833d Mon Sep 17 00:00:00 2001 From: Shizuo Fujita Date: Tue, 8 Jul 2025 12:30:16 +0900 Subject: [PATCH 2/7] Add connect_timeout / resolve_timeout option to TCPSocket.new Signed-off-by: Shizuo Fujita --- fluent-logger.gemspec | 2 +- lib/fluent/logger/fluent_logger.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fluent-logger.gemspec b/fluent-logger.gemspec index d8b4e1d..71f9bbd 100644 --- a/fluent-logger.gemspec +++ b/fluent-logger.gemspec @@ -21,7 +21,7 @@ Gem::Specification.new do |gem| gem.require_paths = ['lib'] gem.license = "Apache-2.0" - gem.required_ruby_version = '>= 2.7' + gem.required_ruby_version = '>= 3.0' gem.add_dependency "msgpack", ">= 1.0.0", "< 2" diff --git a/lib/fluent/logger/fluent_logger.rb b/lib/fluent/logger/fluent_logger.rb index baa7375..fd7fb90 100644 --- a/lib/fluent/logger/fluent_logger.rb +++ b/lib/fluent/logger/fluent_logger.rb @@ -173,7 +173,7 @@ def create_socket! if @socket_path @con = UNIXSocket.new(@socket_path) else - @con = Socket.tcp(@host, @port, connect_timeout: @connect_timeout, resolv_timeout: @resolv_timeout) + @con = TCPSocket.new(@host, @port, connect_timeout: @connect_timeout, resolv_timeout: @resolv_timeout) if @tls_options context = OpenSSL::SSL::SSLContext.new if @tls_options[:insecure] From 34291fb576c470f5a08d9ffc4be5ada2d78e4d1f Mon Sep 17 00:00:00 2001 From: Shizuo Fujita Date: Wed, 9 Jul 2025 11:28:52 +0900 Subject: [PATCH 3/7] Use timeout parameters when run on supported Ruby version Signed-off-by: Shizuo Fujita --- README.md | 4 ++-- fluent-logger.gemspec | 2 -- lib/fluent/logger/fluent_logger.rb | 10 +++++++++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index e22a48f..594cb59 100644 --- a/README.md +++ b/README.md @@ -150,11 +150,11 @@ If `false`, `Logger#post` raises an error when nonblocking write gets `EAGAIN` ( #### connect_timeout (Integer) -Specify timeout in seconds from connecting. Default: `nil` +Specify timeout in seconds from connecting. This parameter is available with Ruby 3.0 or above. Default: `nil` #### resolve_timeout (Integer) -Specify timeout in seconds from when the hostname resolution starts. Default: `nil` +Specify timeout in seconds from when the hostname resolution starts. This parameter is available with Ruby 3.0 or above. Default: `nil` #### buffer_overflow_handler (Proc) diff --git a/fluent-logger.gemspec b/fluent-logger.gemspec index 71f9bbd..8811ae6 100644 --- a/fluent-logger.gemspec +++ b/fluent-logger.gemspec @@ -21,8 +21,6 @@ Gem::Specification.new do |gem| gem.require_paths = ['lib'] gem.license = "Apache-2.0" - gem.required_ruby_version = '>= 3.0' - gem.add_dependency "msgpack", ">= 1.0.0", "< 2" # logger gem that isn't default gems as of Ruby 3.5 diff --git a/lib/fluent/logger/fluent_logger.rb b/lib/fluent/logger/fluent_logger.rb index fd7fb90..8f1f54d 100644 --- a/lib/fluent/logger/fluent_logger.rb +++ b/lib/fluent/logger/fluent_logger.rb @@ -173,7 +173,11 @@ def create_socket! if @socket_path @con = UNIXSocket.new(@socket_path) else - @con = TCPSocket.new(@host, @port, connect_timeout: @connect_timeout, resolv_timeout: @resolv_timeout) + if supported_timeout? + @con = TCPSocket.new(@host, @port, connect_timeout: @connect_timeout, resolv_timeout: @resolv_timeout) + else + @con = TCPSocket.new(@host, @port) + end if @tls_options context = OpenSSL::SSL::SSLContext.new if @tls_options[:insecure] @@ -381,6 +385,10 @@ def wait_writeable?(e) true end end + + def supported_timeout? + @supported_timeout ||= Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.0.0') + end end end end From 29089bfa4683d8ff995d6ece39ae822bcf1faddc Mon Sep 17 00:00:00 2001 From: Shizuo Fujita Date: Fri, 18 Jul 2025 16:48:28 +0900 Subject: [PATCH 4/7] Add tests for timeout Signed-off-by: Shizuo Fujita --- spec/fluent_logger_spec.rb | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/spec/fluent_logger_spec.rb b/spec/fluent_logger_spec.rb index b597e58..b1e2607 100644 --- a/spec/fluent_logger_spec.rb +++ b/spec/fluent_logger_spec.rb @@ -6,6 +6,7 @@ require 'logger' require 'stringio' require 'fluent/logger/fluent_logger/cui' +require 'timeout' describe Fluent::Logger::FluentLogger do let(:fluentd) { @@ -434,4 +435,24 @@ def flush(messages) } end end + + if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.0.0') + context "timeout" do + it ('support connect_timeout') { + Timeout::timeout(5) do + # Use invalid IP address to make sure that the connection will timeout. + # (192.0.2.0 is a special IP address that can be used in only documentation. Ref. RFC 5737) + logger = Fluent::Logger::FluentLogger.new(nil, host: '192.0.2.0', port: fluentd.port, connect_timeout: 1) + expect(logger.last_error).to be_a_kind_of(IO::TimeoutError) + end + } + it ('support resolv_timeout') { + expect { + # It just checks that the resolv_timeout option is supported + # because it can't use a stub for the DNS resolution. + Fluent::Logger::FluentLogger.new(nil, host: 'localhost', port: fluentd.port, resolv_timeout: 1) + }.to_not raise_error + } + end + end end From feedded2854106602e15f32603425112b0140788 Mon Sep 17 00:00:00 2001 From: Shizuo Fujita Date: Fri, 8 Aug 2025 18:07:50 +0900 Subject: [PATCH 5/7] Fix typo Signed-off-by: Shizuo Fujita --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 594cb59..92791eb 100644 --- a/README.md +++ b/README.md @@ -152,7 +152,7 @@ If `false`, `Logger#post` raises an error when nonblocking write gets `EAGAIN` ( Specify timeout in seconds from connecting. This parameter is available with Ruby 3.0 or above. Default: `nil` -#### resolve_timeout (Integer) +#### resolv_timeout (Integer) Specify timeout in seconds from when the hostname resolution starts. This parameter is available with Ruby 3.0 or above. Default: `nil` From 335e4ad7a1a5c5822c967680e4894ab42b594a6c Mon Sep 17 00:00:00 2001 From: Shizuo Fujita Date: Sat, 9 Aug 2025 16:12:40 +0900 Subject: [PATCH 6/7] Use Timeout class instead Signed-off-by: Shizuo Fujita --- README.md | 8 ++------ lib/fluent/logger/fluent_logger.rb | 14 ++++---------- spec/fluent_logger_spec.rb | 25 +++++++------------------ 3 files changed, 13 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 92791eb..72419f7 100644 --- a/README.md +++ b/README.md @@ -148,13 +148,9 @@ Use nonblocking write(`IO#write_nonblock`) instead of normal write(`IO#write`). If `false`, `Logger#post` raises an error when nonblocking write gets `EAGAIN` (i.e. `use_nonblock` must be `true`, otherwise this will have no effect). Default: `true` -#### connect_timeout (Integer) +#### timeout (Integer) -Specify timeout in seconds from connecting. This parameter is available with Ruby 3.0 or above. Default: `nil` - -#### resolv_timeout (Integer) - -Specify timeout in seconds from when the hostname resolution starts. This parameter is available with Ruby 3.0 or above. Default: `nil` +Specify a timeout in seconds for connecting. Default: `0` #### buffer_overflow_handler (Proc) diff --git a/lib/fluent/logger/fluent_logger.rb b/lib/fluent/logger/fluent_logger.rb index 8f1f54d..2aef0a2 100644 --- a/lib/fluent/logger/fluent_logger.rb +++ b/lib/fluent/logger/fluent_logger.rb @@ -22,6 +22,7 @@ require 'monitor' require 'logger' require 'json' +require 'timeout' module Fluent module Logger @@ -115,8 +116,7 @@ def initialize(tag_prefix = nil, *args) @wait_writeable = true @wait_writeable = options[:wait_writeable] if options.key?(:wait_writeable) - @connect_timeout = options[:connect_timeout] - @resolv_timeout = options[:resolv_timeout] + @timeout = options[:timeout] || 0 @last_error = {} @@ -173,10 +173,8 @@ def create_socket! if @socket_path @con = UNIXSocket.new(@socket_path) else - if supported_timeout? - @con = TCPSocket.new(@host, @port, connect_timeout: @connect_timeout, resolv_timeout: @resolv_timeout) - else - @con = TCPSocket.new(@host, @port) + @con = Timeout.timeout(@timeout) do + TCPSocket.new(@host, @port) end if @tls_options context = OpenSSL::SSL::SSLContext.new @@ -385,10 +383,6 @@ def wait_writeable?(e) true end end - - def supported_timeout? - @supported_timeout ||= Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.0.0') - end end end end diff --git a/spec/fluent_logger_spec.rb b/spec/fluent_logger_spec.rb index b1e2607..aa67c8c 100644 --- a/spec/fluent_logger_spec.rb +++ b/spec/fluent_logger_spec.rb @@ -436,23 +436,12 @@ def flush(messages) end end - if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.0.0') - context "timeout" do - it ('support connect_timeout') { - Timeout::timeout(5) do - # Use invalid IP address to make sure that the connection will timeout. - # (192.0.2.0 is a special IP address that can be used in only documentation. Ref. RFC 5737) - logger = Fluent::Logger::FluentLogger.new(nil, host: '192.0.2.0', port: fluentd.port, connect_timeout: 1) - expect(logger.last_error).to be_a_kind_of(IO::TimeoutError) - end - } - it ('support resolv_timeout') { - expect { - # It just checks that the resolv_timeout option is supported - # because it can't use a stub for the DNS resolution. - Fluent::Logger::FluentLogger.new(nil, host: 'localhost', port: fluentd.port, resolv_timeout: 1) - }.to_not raise_error - } + it ('support timeout') { + Timeout::timeout(5) do + # Use invalid IP address to make sure that the connection will timeout. + # (192.0.2.0 is a special IP address that can be used in only documentation. Ref. RFC 5737) + logger = Fluent::Logger::FluentLogger.new(nil, host: '192.0.2.0', port: fluentd.port, timeout: 1) + expect(logger.last_error).to be_a_kind_of(Timeout::Error) end - end + } end From 26a6ee0ba6b2d777563a6dcb20176110cc77f13e Mon Sep 17 00:00:00 2001 From: Daijiro Fukuda Date: Mon, 1 Sep 2025 18:30:57 +0900 Subject: [PATCH 7/7] README: add note for the default value Signed-off-by: Daijiro Fukuda --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 72419f7..78c12a8 100644 --- a/README.md +++ b/README.md @@ -150,7 +150,7 @@ If `false`, `Logger#post` raises an error when nonblocking write gets `EAGAIN` ( #### timeout (Integer) -Specify a timeout in seconds for connecting. Default: `0` +Specify a timeout in seconds for connecting. Default: `0` (Disabled) #### buffer_overflow_handler (Proc)