From 7f966fe057f7c415fe194339fef98e14758bb530 Mon Sep 17 00:00:00 2001 From: nick evans Date: Sun, 19 Apr 2026 14:58:24 -0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=8D=20Improve=20debug=20connection=20t?= =?UTF-8?q?race=20output?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This uses String#dump to print out control characters legibly, whic makes the CRLF line endings explicit and enables reliable copy/pasting of logged data for tests or debugging. This also improves how sent/rcvd data is interleaved (in my opinion). Note that, because client-sent data is generally in the main/application thread(s) (inside `#synchronize`), and server responses are received in the server thread (_not_ synchronized), this did have a threading race condition. So this updated version uses `synchronize` to log the server responses. --- lib/net/imap.rb | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/lib/net/imap.rb b/lib/net/imap.rb index 6607f786..e0824c15 100644 --- a/lib/net/imap.rb +++ b/lib/net/imap.rb @@ -1111,7 +1111,7 @@ def initialize(host, port: nil, ssl: nil, response_handlers: nil, # Basic Client State @utf8_strings = false - @debug_output_bol = true + @debug_output_line = nil @exception = nil @greeting = nil @capabilities = nil @@ -3586,7 +3586,7 @@ def get_tagged_response(tag, cmd, timeout = nil) def get_response buff = @reader.read_response_buffer return nil if buff.length == 0 - $stderr.print(buff.gsub(/^/n, "S: ")) if config.debug? + synchronize do print_debug_trace("S: ", buff) end if config.debug? @parser.parse(buff) end @@ -3671,15 +3671,20 @@ def generate_tag def put_string(str) @sock.print(str) - if config.debug? - if @debug_output_bol - $stderr.print("C: ") + print_debug_trace("C: ", str) if config.debug? + end + + def print_debug_trace(prefix, str) + str.each_line do |line| + if @debug_output_line.nil? then $stderr.print prefix + elsif @debug_output_line != prefix then $stderr.print "\n", prefix end - $stderr.print(str.gsub(/\n/n) { $'.empty? ? $& : "\nC: " }) - if /\n\z/n.match(str) - @debug_output_bol = true + if /\n\z/n.match?(line) + $stderr.puts line.dump.delete_prefix('"').delete_suffix('"') + @debug_output_line = nil else - @debug_output_bol = false + $stderr.print line.dump.delete_prefix('"').delete_suffix('"') + @debug_output_line = prefix end end end