diff --git a/examples/puma/client-certs/run_server_with_certs.rb b/examples/puma/client-certs/run_server_with_certs.rb index 6df57b67..22d7580d 100644 --- a/examples/puma/client-certs/run_server_with_certs.rb +++ b/examples/puma/client-certs/run_server_with_certs.rb @@ -8,8 +8,8 @@ app = proc {|env| p env['puma.peercert'] [200, {}, [ env['puma.peercert'] ]] } -events = Puma::Events.new($stdout, $stderr) -server = Puma::Server.new(app, events) +log_writer = Puma::LogWriter.new($stdout, $stderr) +server = Puma::Server.new(app, log_writer) context = Puma::MiniSSL::Context.new context.key = "certs/server.key" diff --git a/lib/puma/binder.rb b/lib/puma/binder.rb index 300ece14..67c58ee3 100644 --- a/lib/puma/binder.rb +++ b/lib/puma/binder.rb @@ -28,8 +28,8 @@ module Puma RACK_VERSION = [1,6].freeze - def initialize(events, conf = Configuration.new) - @events = events + def initialize(log_writer, conf = Configuration.new) + @log_writer = log_writer @conf = conf @listeners = [] @inherited_fds = {} @@ -38,7 +38,7 @@ module Puma @proto_env = { "rack.version".freeze => RACK_VERSION, - "rack.errors".freeze => events.stderr, + "rack.errors".freeze => log_writer.stderr, "rack.multithread".freeze => conf.options[:max_threads] > 1, "rack.multiprocess".freeze => conf.options[:workers] >= 1, "rack.run_once".freeze => false, @@ -98,7 +98,7 @@ module Puma # @version 5.0.0 # def create_activated_fds(env_hash) - @events.debug "ENV['LISTEN_FDS'] #{ENV['LISTEN_FDS'].inspect} env_hash['LISTEN_PID'] #{env_hash['LISTEN_PID'].inspect}" + @log_writer.debug "ENV['LISTEN_FDS'] #{ENV['LISTEN_FDS'].inspect} env_hash['LISTEN_PID'] #{env_hash['LISTEN_PID'].inspect}" return [] unless env_hash['LISTEN_FDS'] && env_hash['LISTEN_PID'].to_i == $$ env_hash['LISTEN_FDS'].to_i.times do |index| sock = TCPServer.for_fd(socket_activation_fd(index)) @@ -110,7 +110,7 @@ module Puma [:tcp, addr, port] end @activated_sockets[key] = sock - @events.debug "Registered #{key.join ':'} for activation from LISTEN_FDS" + @log_writer.debug "Registered #{key.join ':'} for activation from LISTEN_FDS" end ["LISTEN_FDS", "LISTEN_PID"] # Signal to remove these keys from ENV end @@ -152,17 +152,17 @@ module Puma end end - def parse(binds, logger, log_msg = 'Listening') + def parse(binds, log_writer, log_msg = 'Listening') binds.each do |str| uri = URI.parse str case uri.scheme when "tcp" if fd = @inherited_fds.delete(str) io = inherit_tcp_listener uri.host, uri.port, fd - logger.log "* Inherited #{str}" + log_writer.log "* Inherited #{str}" elsif sock = @activated_sockets.delete([ :tcp, uri.host, uri.port ]) io = inherit_tcp_listener uri.host, uri.port, sock - logger.log "* Activated #{str}" + log_writer.log "* Activated #{str}" else ios_len = @ios.length params = Util.parse_query uri.query @@ -174,7 +174,7 @@ module Puma @ios[ios_len..-1].each do |i| addr = loc_addr_str i - logger.log "* #{log_msg} on http://#{addr}" + log_writer.log "* #{log_msg} on http://#{addr}" end end @@ -191,12 +191,12 @@ module Puma if fd = @inherited_fds.delete(str) @unix_paths << path unless abstract io = inherit_unix_listener path, fd - logger.log "* Inherited #{str}" + log_writer.log "* Inherited #{str}" elsif sock = @activated_sockets.delete([ :unix, path ]) || @activated_sockets.delete([ :unix, File.realdirpath(path) ]) @unix_paths << path unless abstract || File.exist?(path) io = inherit_unix_listener path, sock - logger.log "* Activated #{str}" + log_writer.log "* Activated #{str}" else umask = nil mode = nil @@ -220,7 +220,7 @@ module Puma @unix_paths << path unless abstract || File.exist?(path) io = add_unix_listener path, umask, mode, backlog - logger.log "* #{log_msg} on #{str}" + log_writer.log "* #{log_msg} on #{str}" end @listeners << [str, io] @@ -246,15 +246,15 @@ module Puma params["#{v}_pem"] = @conf.options[:store][index] end end - MiniSSL::ContextBuilder.new(params, @events).context + MiniSSL::ContextBuilder.new(params, @log_writer).context end if fd = @inherited_fds.delete(str) - logger.log "* Inherited #{str}" + log_writer.log "* Inherited #{str}" io = inherit_ssl_listener fd, ctx elsif sock = @activated_sockets.delete([ :tcp, uri.host, uri.port ]) io = inherit_ssl_listener sock, ctx - logger.log "* Activated #{str}" + log_writer.log "* Activated #{str}" else ios_len = @ios.length backlog = params.fetch('backlog', 1024).to_i @@ -262,20 +262,20 @@ module Puma @ios[ios_len..-1].each do |i| addr = loc_addr_str i - logger.log "* #{log_msg} on ssl://#{addr}?#{uri.query}" + log_writer.log "* #{log_msg} on ssl://#{addr}?#{uri.query}" end end @listeners << [str, io] if io else - logger.error "Invalid URI: #{str}" + log_writer.error "Invalid URI: #{str}" end end # If we inherited fds but didn't use them (because of a # configuration change), then be sure to close them. @inherited_fds.each do |str, fd| - logger.log "* Closing unused inherited connection: #{str}" + log_writer.log "* Closing unused inherited connection: #{str}" begin IO.for_fd(fd).close @@ -295,7 +295,7 @@ module Puma fds = @ios.map(&:to_i) @activated_sockets.each do |key, sock| next if fds.include? sock.to_i - logger.log "* Closing unused activated socket: #{key.first}://#{key[1..-1].join ':'}" + log_writer.log "* Closing unused activated socket: #{key.first}://#{key[1..-1].join ':'}" begin sock.close rescue SystemCallError @@ -319,7 +319,7 @@ module Puma local_certificates_path = File.expand_path("~/.localhost") [File.join(local_certificates_path, "localhost.key"), File.join(local_certificates_path, "localhost.crt")] end - MiniSSL::ContextBuilder.new({ "key" => key_path, "cert" => crt_path }, @events).context + MiniSSL::ContextBuilder.new({ "key" => key_path, "cert" => crt_path }, @log_writer).context end # Tell the server to listen on host +host+, port +port+. diff --git a/lib/puma/cli.rb b/lib/puma/cli.rb index 16e0ace6..fa8cc866 100644 --- a/lib/puma/cli.rb +++ b/lib/puma/cli.rb @@ -7,7 +7,7 @@ require 'puma' require 'puma/configuration' require 'puma/launcher' require 'puma/const' -require 'puma/events' +require 'puma/log_writer' module Puma class << self @@ -30,10 +30,10 @@ module Puma # +stdout+ and +stderr+ can be set to IO-like objects which # this object will report status on. # - def initialize(argv, events=Events.stdio) + def initialize(argv, log_writer = LogWriter.stdio, events = Events.new) @debug = false @argv = argv.dup - + @log_writer = log_writer @events = events @conf = nil @@ -69,7 +69,7 @@ module Puma end end - @launcher = Puma::Launcher.new(@conf, :events => @events, :argv => argv) + @launcher = Puma::Launcher.new(@conf, :log_writer => @log_writer, :events => @events, :argv => argv) end attr_reader :launcher @@ -83,7 +83,7 @@ module Puma private def unsupported(str) - @events.error(str) + @log_writer.error(str) raise UnsupportedOption end @@ -186,7 +186,7 @@ module Puma end o.on "-s", "--silent", "Do not log prompt messages other than errors" do - @events = Events.new NullIO.new, $stderr + @log_writer = LogWriter.new(NullIO.new, $stderr) end o.on "-S", "--state PATH", "Where to store the state details" do |arg| diff --git a/lib/puma/cluster.rb b/lib/puma/cluster.rb index 2862228b..5c5e2c72 100644 --- a/lib/puma/cluster.rb +++ b/lib/puma/cluster.rb @@ -17,8 +17,8 @@ module Puma # via the `spawn_workers` method call. Each worker will have it's own # instance of a `Puma::Server`. class Cluster < Runner - def initialize(cli, events) - super cli, events + def initialize(launcher) + super(launcher) @phase = 0 @workers = [] @@ -96,7 +96,7 @@ module Puma # @version 5.0.0 def spawn_worker(idx, master) - @launcher.config.run_hooks :before_worker_fork, idx, @launcher.events + @launcher.config.run_hooks(:before_worker_fork, idx, @launcher.log_writer) pid = fork { worker(idx, master) } if !pid @@ -105,7 +105,7 @@ module Puma exit! 1 end - @launcher.config.run_hooks :after_worker_fork, idx, @launcher.events + @launcher.config.run_hooks(:after_worker_fork, idx, @launcher.log_writer) pid end @@ -413,8 +413,8 @@ module Puma @master_read, @worker_write = read, @wakeup - @launcher.config.run_hooks :before_fork, nil, @launcher.events - Puma::Util.nakayoshi_gc @events if @options[:nakayoshi_fork] + @launcher.config.run_hooks(:before_fork, nil, @launcher.log_writer) + Puma::Util.nakayoshi_gc(@log_writer) if @options[:nakayoshi_fork] spawn_workers diff --git a/lib/puma/cluster/worker.rb b/lib/puma/cluster/worker.rb index 5cc48898..10e3a9d8 100644 --- a/lib/puma/cluster/worker.rb +++ b/lib/puma/cluster/worker.rb @@ -12,7 +12,7 @@ module Puma attr_reader :index, :master def initialize(index:, master:, launcher:, pipes:, server: nil) - super launcher, launcher.events + super(launcher) @index = index @master = master @@ -52,7 +52,7 @@ module Puma # Invoke any worker boot hooks so they can get # things in shape before booting the app. - @launcher.config.run_hooks :before_worker_boot, index, @launcher.events + @launcher.config.run_hooks(:before_worker_boot, index, @launcher.log_writer) begin server = @server ||= start_server @@ -83,8 +83,8 @@ module Puma if restart_server.length > 0 restart_server.clear server.begin_restart(true) - @launcher.config.run_hooks :before_refork, nil, @launcher.events - Puma::Util.nakayoshi_gc @events if @options[:nakayoshi_fork] + @launcher.config.run_hooks(:before_refork, nil, @launcher.log_writer) + Puma::Util.nakayoshi_gc(@log_writer) if @options[:nakayoshi_fork] end elsif idx == 0 # restart server restart_server << true << false @@ -138,7 +138,7 @@ module Puma # Invoke any worker shutdown hooks so they can prevent the worker # exiting until any background operations are completed - @launcher.config.run_hooks :before_worker_shutdown, index, @launcher.events + @launcher.config.run_hooks(:before_worker_shutdown, index, @launcher.log_writer) ensure @worker_write << "t#{Process.pid}\n" rescue nil @worker_write.close @@ -147,7 +147,7 @@ module Puma private def spawn_worker(idx) - @launcher.config.run_hooks :before_worker_fork, idx, @launcher.events + @launcher.config.run_hooks(:before_worker_fork, idx, @launcher.log_writer) pid = fork do new_worker = Worker.new index: idx, @@ -165,7 +165,7 @@ module Puma exit! 1 end - @launcher.config.run_hooks :after_worker_fork, idx, @launcher.events + @launcher.config.run_hooks(:after_worker_fork, idx, @launcher.log_writer) pid end end diff --git a/lib/puma/configuration.rb b/lib/puma/configuration.rb index 9871ff02..5c229c72 100644 --- a/lib/puma/configuration.rb +++ b/lib/puma/configuration.rb @@ -291,13 +291,13 @@ module Puma @plugins.create name end - def run_hooks(key, arg, events) + def run_hooks(key, arg, log_writer) @options.all_of(key).each do |b| begin b.call arg rescue => e - events.log "WARNING hook #{key} failed with exception (#{e.class}) #{e.message}" - events.debug e.backtrace.join("\n") + log_writer.log "WARNING hook #{key} failed with exception (#{e.class}) #{e.message}" + log_writer.debug e.backtrace.join("\n") end end end diff --git a/lib/puma/control_cli.rb b/lib/puma/control_cli.rb index efa3a86e..23030962 100644 --- a/lib/puma/control_cli.rb +++ b/lib/puma/control_cli.rb @@ -293,13 +293,13 @@ module Puma run_args += ["-C", @config_file] if @config_file run_args += ["-e", @environment] if @environment - events = Puma::Events.new @stdout, @stderr + log_writer = Puma::LogWriter.new(@stdout, @stderr) # replace $0 because puma use it to generate restart command puma_cmd = $0.gsub(/pumactl$/, 'puma') $0 = puma_cmd if File.exist?(puma_cmd) - cli = Puma::CLI.new run_args, events + cli = Puma::CLI.new run_args, log_writer cli.run end end diff --git a/lib/puma/events.rb b/lib/puma/events.rb index f96d5538..3ada3e13 100644 --- a/lib/puma/events.rb +++ b/lib/puma/events.rb @@ -1,52 +1,23 @@ # frozen_string_literal: true -require "puma/null_io" -require 'puma/error_logger' -require 'stringio' - module Puma - # The default implement of an event sink object used by Server - # for when certain kinds of events occur in the life of the server. - # - # The methods available are the events that the Server fires. - # + + # This is an event sink used by `Puma::Server` to handle + # lifecycle events such as :on_booted, :on_restart, and :on_stopped. + # Using `Puma::DSL` it is possible to register callback hooks + # for each event type. class Events - class DefaultFormatter - def call(str) - str - end - end - - class PidFormatter - def call(str) - "[#{$$}] #{str}" - end - end - - # Create an Events object that prints to +stdout+ and +stderr+. - # - def initialize(stdout, stderr) - @formatter = DefaultFormatter.new - @stdout = stdout - @stderr = stderr - - @debug = ENV.key? 'PUMA_DEBUG' - @error_logger = ErrorLogger.new(@stderr) + def initialize @hooks = Hash.new { |h,k| h[k] = [] } end - attr_reader :stdout, :stderr - attr_accessor :formatter - # Fire callbacks for the named hook - # def fire(hook, *args) @hooks[hook].each { |t| t.call(*args) } end # Register a callback for a given hook - # def register(hook, obj=nil, &blk) if obj and blk raise "Specify either an object or a block, not both" @@ -59,79 +30,6 @@ module Puma h end - # Write +str+ to +@stdout+ - # - def log(str) - @stdout.puts format(str) if @stdout.respond_to? :puts - - @stdout.flush unless @stdout.sync - rescue Errno::EPIPE - end - - def write(str) - @stdout.write format(str) - end - - def debug(str) - log("% #{str}") if @debug - end - - # Write +str+ to +@stderr+ - # - def error(str) - @error_logger.info(text: format("ERROR: #{str}")) - exit 1 - end - - def format(str) - formatter.call(str) - end - - # An HTTP connection error has occurred. - # +error+ a connection exception, +req+ the request, - # and +text+ additional info - # @version 5.0.0 - # - def connection_error(error, req, text="HTTP connection error") - @error_logger.info(error: error, req: req, text: text) - end - - # An HTTP parse error has occurred. - # +error+ a parsing exception, - # and +req+ the request. - # - def parse_error(error, req) - @error_logger.info(error: error, req: req, text: 'HTTP parse error, malformed request') - end - - # An SSL error has occurred. - # @param error - # @param ssl_socket - # - def ssl_error(error, ssl_socket) - peeraddr = ssl_socket.peeraddr.last rescue "" - peercert = ssl_socket.peercert - subject = peercert ? peercert.subject : nil - @error_logger.info(error: error, text: "SSL error, peer: #{peeraddr}, peer cert: #{subject}") - end - - # An unknown error has occurred. - # +error+ an exception object, +req+ the request, - # and +text+ additional info - # - def unknown_error(error, req=nil, text="Unknown error") - @error_logger.info(error: error, req: req, text: text) - end - - # Log occurred error debug dump. - # +error+ an exception object, +req+ the request, - # and +text+ additional info - # @version 5.0.0 - # - def debug_error(error, req=nil, text="") - @error_logger.debug(error: error, req: req, text: text) - end - def on_booted(&block) register(:on_booted, &block) end @@ -155,23 +53,5 @@ module Puma def fire_on_stopped! fire(:on_stopped) end - - DEFAULT = new(STDOUT, STDERR) - - # Returns an Events object which writes its status to 2 StringIO - # objects. - # - def self.strings - Events.new StringIO.new, StringIO.new - end - - def self.stdio - Events.new $stdout, $stderr - end - - def self.null - n = NullIO.new - Events.new n, n - end end end diff --git a/lib/puma/launcher.rb b/lib/puma/launcher.rb index 63202374..d0f8374b 100644 --- a/lib/puma/launcher.rb +++ b/lib/puma/launcher.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true +require 'puma/log_writer' require 'puma/events' require 'puma/detect' require 'puma/cluster' @@ -27,7 +28,7 @@ module Puma # +conf+ A Puma::Configuration object indicating how to run the server. # # +launcher_args+ A Hash that currently has one required key `:events`, - # this is expected to hold an object similar to an `Puma::Events.stdio`, + # this is expected to hold an object similar to an `Puma::LogWriter.stdio`, # this object will be responsible for broadcasting Puma's internal state # to a logging destination. An optional key `:argv` can be supplied, # this should be an array of strings, these arguments are re-used when @@ -41,15 +42,16 @@ module Puma # [200, {}, ["hello world"]] # end # end - # Puma::Launcher.new(conf, events: Puma::Events.stdio).run + # Puma::Launcher.new(conf, log_writer: Puma::LogWriter.stdio).run def initialize(conf, launcher_args={}) @runner = nil - @events = launcher_args[:events] || Events::DEFAULT + @log_writer = launcher_args[:log_writer] || LogWriter::DEFAULT + @events = launcher_args[:events] || Events.new @argv = launcher_args[:argv] || [] @original_argv = @argv.dup @config = conf - @binder = Binder.new(@events, conf) + @binder = Binder.new(@log_writer, conf) @binder.create_inherited_fds(ENV).each { |k| ENV.delete k } @binder.create_activated_fds(ENV).each { |k| ENV.delete k } @@ -70,8 +72,8 @@ module Puma @options = @config.options @config.clamp - @events.formatter = Events::PidFormatter.new if clustered? - @events.formatter = options[:log_formatter] if @options[:log_formatter] + @log_writer.formatter = LogWriter::PidFormatter.new if clustered? + @log_writer.formatter = options[:log_formatter] if @options[:log_formatter] generate_restart_data @@ -87,11 +89,11 @@ module Puma set_rack_environment if clustered? - @options[:logger] = @events + @options[:logger] = @log_writer - @runner = Cluster.new(self, @events) + @runner = Cluster.new(self) else - @runner = Single.new(self, @events) + @runner = Single.new(self) end Puma.stats_object = @runner @@ -100,7 +102,7 @@ module Puma log_config if ENV['PUMA_LOG_CONFIG'] end - attr_reader :binder, :events, :config, :options, :restart_dir + attr_reader :binder, :log_writer, :events, :config, :options, :restart_dir # Return stats about the server def stats @@ -263,7 +265,7 @@ module Puma def restart! @events.fire_on_restart! - @config.run_hooks :on_restart, self, @events + @config.run_hooks :on_restart, self, @log_writer if Puma.jruby? close_binder_listeners @@ -317,13 +319,13 @@ module Puma log "* Enabling systemd notification integration" - systemd = Systemd.new(@events) + systemd = Systemd.new(@log_writer, @events) systemd.hook_events systemd.start_watchdog end def log(str) - @events.log str + @log_writer.log(str) end def clustered? @@ -331,7 +333,7 @@ module Puma end def unsupported(str) - @events.error(str) + @log_writer.error(str) raise UnsupportedOption end @@ -362,7 +364,7 @@ module Puma def prune_bundler! return unless prune_bundler? - BundlePruner.new(@original_argv, @options[:extra_runtime_dependencies], @events).prune + BundlePruner.new(@original_argv, @options[:extra_runtime_dependencies], @log_writer).prune end def generate_restart_data @@ -464,8 +466,8 @@ module Puma unless Puma.jruby? # INFO in use by JVM already Signal.trap "SIGINFO" do thread_status do |name, backtrace| - @events.log name - @events.log backtrace.map { |bt| " #{bt}" } + @log_writer.log(name) + @log_writer.log(backtrace.map { |bt| " #{bt}" }) end end end diff --git a/lib/puma/launcher/bundle_pruner.rb b/lib/puma/launcher/bundle_pruner.rb index ef8bade8..a33858e9 100644 --- a/lib/puma/launcher/bundle_pruner.rb +++ b/lib/puma/launcher/bundle_pruner.rb @@ -7,10 +7,10 @@ module Puma # application restarts. class BundlePruner - def initialize(original_argv, extra_runtime_dependencies, events) + def initialize(original_argv, extra_runtime_dependencies, log_writer) @original_argv = Array(original_argv) @extra_runtime_dependencies = Array(extra_runtime_dependencies) - @events = events + @log_writer = log_writer end def prune @@ -96,7 +96,7 @@ module Puma end def log(str) - @events.log(str) + @log_writer.log(str) end end end diff --git a/lib/puma/log_writer.rb b/lib/puma/log_writer.rb new file mode 100644 index 00000000..b765aba3 --- /dev/null +++ b/lib/puma/log_writer.rb @@ -0,0 +1,123 @@ +# frozen_string_literal: true + +require 'puma/null_io' +require 'puma/error_logger' +require 'stringio' + +module Puma + + # Handles logging concerns for both standard messages + # (+stdout+) and errors (+stderr+). + class LogWriter + + class DefaultFormatter + def call(str) + str + end + end + + class PidFormatter + def call(str) + "[#{$$}] #{str}" + end + end + + attr_reader :stdout, + :stderr + + attr_accessor :formatter + + # Create a LogWriter that prints to +stdout+ and +stderr+. + def initialize(stdout, stderr) + @formatter = DefaultFormatter.new + @stdout = stdout + @stderr = stderr + + @debug = ENV.key?('PUMA_DEBUG') + @error_logger = ErrorLogger.new(@stderr) + end + + DEFAULT = new(STDOUT, STDERR) + + # Returns an LogWriter object which writes its status to + # two StringIO objects. + def self.strings + LogWriter.new(StringIO.new, StringIO.new) + end + + def self.stdio + LogWriter.new($stdout, $stderr) + end + + def self.null + n = NullIO.new + LogWriter.new(n, n) + end + + # Write +str+ to +@stdout+ + def log(str) + @stdout.puts(format(str)) if @stdout.respond_to? :puts + + @stdout.flush unless @stdout.sync + rescue Errno::EPIPE + end + + def write(str) + @stdout.write(format(str)) + end + + def debug(str) + log("% #{str}") if @debug + end + + # Write +str+ to +@stderr+ + def error(str) + @error_logger.info(text: format("ERROR: #{str}")) + exit 1 + end + + def format(str) + formatter.call(str) + end + + # An HTTP connection error has occurred. + # +error+ a connection exception, +req+ the request, + # and +text+ additional info + # @version 5.0.0 + def connection_error(error, req, text="HTTP connection error") + @error_logger.info(error: error, req: req, text: text) + end + + # An HTTP parse error has occurred. + # +error+ a parsing exception, + # and +req+ the request. + def parse_error(error, req) + @error_logger.info(error: error, req: req, text: 'HTTP parse error, malformed request') + end + + # An SSL error has occurred. + # @param error + # @param ssl_socket + def ssl_error(error, ssl_socket) + peeraddr = ssl_socket.peeraddr.last rescue "" + peercert = ssl_socket.peercert + subject = peercert ? peercert.subject : nil + @error_logger.info(error: error, text: "SSL error, peer: #{peeraddr}, peer cert: #{subject}") + end + + # An unknown error has occurred. + # +error+ an exception object, +req+ the request, + # and +text+ additional info + def unknown_error(error, req=nil, text="Unknown error") + @error_logger.info(error: error, req: req, text: text) + end + + # Log occurred error debug dump. + # +error+ an exception object, +req+ the request, + # and +text+ additional info + # @version 5.0.0 + def debug_error(error, req=nil, text="") + @error_logger.debug(error: error, req: req, text: text) + end + end +end diff --git a/lib/puma/minissl/context_builder.rb b/lib/puma/minissl/context_builder.rb index 8cf16bbd..138d8984 100644 --- a/lib/puma/minissl/context_builder.rb +++ b/lib/puma/minissl/context_builder.rb @@ -11,27 +11,27 @@ module Puma if defined?(JRUBY_VERSION) unless params['keystore'] - events.error "Please specify the Java keystore via 'keystore='" + log_writer.error "Please specify the Java keystore via 'keystore='" end ctx.keystore = params['keystore'] unless params['keystore-pass'] - events.error "Please specify the Java keystore password via 'keystore-pass='" + log_writer.error "Please specify the Java keystore password via 'keystore-pass='" end ctx.keystore_pass = params['keystore-pass'] ctx.ssl_cipher_list = params['ssl_cipher_list'] if params['ssl_cipher_list'] else if params['key'].nil? && params['key_pem'].nil? - events.error "Please specify the SSL key via 'key=' or 'key_pem='" + log_writer.error "Please specify the SSL key via 'key=' or 'key_pem='" end ctx.key = params['key'] if params['key'] ctx.key_pem = params['key_pem'] if params['key_pem'] if params['cert'].nil? && params['cert_pem'].nil? - events.error "Please specify the SSL cert via 'cert=' or 'cert_pem='" + log_writer.error "Please specify the SSL cert via 'cert=' or 'cert_pem='" end ctx.cert = params['cert'] if params['cert'] @@ -39,7 +39,7 @@ module Puma if ['peer', 'force_peer'].include?(params['verify_mode']) unless params['ca'] - events.error "Please specify the SSL ca via 'ca='" + log_writer.error "Please specify the SSL ca via 'ca='" end end @@ -59,7 +59,7 @@ module Puma when "none" MiniSSL::VERIFY_NONE else - events.error "Please specify a valid verify_mode=" + log_writer.error "Please specify a valid verify_mode=" MiniSSL::VERIFY_NONE end end diff --git a/lib/puma/request.rb b/lib/puma/request.rb index c9f4c547..10508c8d 100644 --- a/lib/puma/request.rb +++ b/lib/puma/request.rb @@ -58,7 +58,7 @@ module Puma begin fast_write io, str_early_hints(headers) rescue ConnectionError => e - @events.debug_error e + @log_writer.debug_error e # noop, if we lost the socket we just won't send the early hints end } @@ -89,12 +89,12 @@ module Puma return :async end rescue ThreadPool::ForceShutdown => e - @events.unknown_error e, client, "Rack app" - @events.log "Detected force shutdown of a thread" + @log_writer.unknown_error e, client, "Rack app" + @log_writer.log "Detected force shutdown of a thread" status, headers, res_body = lowlevel_error(e, env, 503) rescue Exception => e - @events.unknown_error e, client, "Rack app" + @log_writer.unknown_error e, client, "Rack app" status, headers, res_body = lowlevel_error(e, env, 500) end diff --git a/lib/puma/runner.rb b/lib/puma/runner.rb index e627892c..8553f664 100644 --- a/lib/puma/runner.rb +++ b/lib/puma/runner.rb @@ -8,10 +8,11 @@ module Puma # serve requests. This class spawns a new instance of `Puma::Server` via # a call to `start_server`. class Runner - def initialize(cli, events) - @launcher = cli - @events = events - @options = cli.options + def initialize(launcher) + @launcher = launcher + @log_writer = launcher.log_writer + @events = launcher.events + @options = launcher.options @app = nil @control = nil @started_at = Time.now @@ -40,7 +41,7 @@ module Puma end def log(str) - @events.log str + @log_writer.log str end # @version 5.0.0 @@ -49,11 +50,11 @@ module Puma end def error(str) - @events.error str + @log_writer.error str end def debug(str) - @events.log "- #{str}" if @options[:debug] + @log_writer.log "- #{str}" if @options[:debug] end def start_control @@ -68,7 +69,7 @@ module Puma app = Puma::App::Status.new @launcher, token - control = Puma::Server.new app, @launcher.events, + control = Puma::Server.new app, @log_writer, @events, { min_threads: 0, max_threads: 1, queue_requests: false } control.binder.parse [str], self, 'Starting control server' @@ -166,8 +167,8 @@ module Puma end def start_server - server = Puma::Server.new app, @launcher.events, @options - server.inherit_binder @launcher.binder + server = Puma::Server.new(app, @log_writer, @events, @options) + server.inherit_binder(@launcher.binder) server end diff --git a/lib/puma/server.rb b/lib/puma/server.rb index f4aed5df..b62f9b97 100644 --- a/lib/puma/server.rb +++ b/lib/puma/server.rb @@ -4,6 +4,7 @@ require 'stringio' require 'puma/thread_pool' require 'puma/const' +require 'puma/log_writer' require 'puma/events' require 'puma/null_io' require 'puma/reactor' @@ -36,6 +37,7 @@ module Puma extend Forwardable attr_reader :thread + attr_reader :log_writer attr_reader :events attr_reader :min_threads, :max_threads # for #stats attr_reader :requests_count # @version 5.0.0 @@ -60,8 +62,9 @@ module Puma # Create a server for the rack app +app+. # - # +events+ is an object which will be called when certain error events occur - # to be handled. See Puma::Events for the list of current methods to implement. + # +log_writer+ is a Puma::LogWriter object used to log info and error messages. + # + # +events+ is a Puma::Events object used to notify application status events. # # Server#run returns a thread that you can join on to wait for the server # to do its work. @@ -70,8 +73,9 @@ module Puma # and have default values set via +fetch+. Normally the values are set via # `::Puma::Configuration.puma_default_options`. # - def initialize(app, events=Events.stdio, options={}) + def initialize(app, log_writer=LogWriter.stdio, events=Events.new, options={}) @app = app + @log_writer = log_writer @events = events @check, @notify = nil @@ -97,7 +101,7 @@ module Puma temp = !!(@options[:environment] =~ /\A(development|test)\z/) @leak_stack_on_error = @options[:environment] ? temp : true - @binder = Binder.new(events) + @binder = Binder.new(log_writer) ENV['RACK_ENV'] ||= "development" @@ -353,11 +357,11 @@ module Puma # In the case that any of the sockets are unexpectedly close. raise rescue StandardError => e - @events.unknown_error e, nil, "Listen loop" + @log_writer.unknown_error e, nil, "Listen loop" end end - @events.debug "Drained #{drain} additional connections." if drain + @log_writer.debug "Drained #{drain} additional connections." if drain @events.fire :state, @status if queue_requests @@ -366,7 +370,7 @@ module Puma end graceful_shutdown if @status == :stop || @status == :restart rescue Exception => e - @events.unknown_error e, nil, "Exception handling servers" + @log_writer.unknown_error e, nil, "Exception handling servers" ensure # RuntimeError is Ruby 2.2 issue, can't modify frozen IOError # Errno::EBADF is infrequently raised @@ -488,7 +492,7 @@ module Puma Puma::Util.purge_interrupt_queue # Already closed rescue StandardError => e - @events.unknown_error e, nil, "Client" + @log_writer.unknown_error e, nil, "Client" end end end @@ -511,13 +515,13 @@ module Puma lowlevel_error(e, client.env) case e when MiniSSL::SSLError - @events.ssl_error e, client.io + @log_writer.ssl_error e, client.io when HttpParserError client.write_error(400) - @events.parse_error e, client + @log_writer.parse_error e, client else client.write_error(500) - @events.unknown_error e, nil, "Read" + @log_writer.unknown_error e, nil, "Read" end end diff --git a/lib/puma/systemd.rb b/lib/puma/systemd.rb index 037e738d..8051b235 100644 --- a/lib/puma/systemd.rb +++ b/lib/puma/systemd.rb @@ -4,7 +4,8 @@ require 'sd_notify' module Puma class Systemd - def initialize(events) + def initialize(log_writer, events) + @log_writer = log_writer @events = events end @@ -40,7 +41,7 @@ module Puma end def log(str) - @events.log str + @log_writer.log(str) end end end diff --git a/lib/puma/util.rb b/lib/puma/util.rb index bf1cabc1..6752735a 100644 --- a/lib/puma/util.rb +++ b/lib/puma/util.rb @@ -31,14 +31,14 @@ module Puma module_function :unescape # @version 5.0.0 - def nakayoshi_gc(events) - events.log "! Promoting existing objects to old generation..." + def nakayoshi_gc(log_writer) + log_writer.log "! Promoting existing objects to old generation..." 4.times { GC.start(full_mark: false) } if GC.respond_to?(:compact) - events.log "! Compacting..." + log_writer.log "! Compacting..." GC.compact end - events.log "! Friendly fork preparation complete." + log_writer.log "! Friendly fork preparation complete." end DEFAULT_SEP = /[&;] */n diff --git a/lib/rack/handler/puma.rb b/lib/rack/handler/puma.rb index d00f2306..e06b5677 100644 --- a/lib/rack/handler/puma.rb +++ b/lib/rack/handler/puma.rb @@ -13,7 +13,7 @@ module Rack def self.config(app, options = {}) require 'puma' require 'puma/configuration' - require 'puma/events' + require 'puma/log_writer' require 'puma/launcher' default_options = DEFAULT_OPTIONS.dup @@ -63,9 +63,9 @@ module Rack def self.run(app, **options) conf = self.config(app, options) - events = options.delete(:Silent) ? ::Puma::Events.strings : ::Puma::Events.stdio + log_writer = options.delete(:Silent) ? ::Puma::LogWriter.strings : ::Puma::LogWriter.stdio - launcher = ::Puma::Launcher.new(conf, :events => events) + launcher = ::Puma::Launcher.new(conf, :log_writer => log_writer) yield launcher if block_given? begin diff --git a/test/helper.rb b/test/helper.rb index f2380625..ae965911 100644 --- a/test/helper.rb +++ b/test/helper.rb @@ -33,8 +33,8 @@ require "puma/detect" # used in various ssl test files, see test_puma_server_ssl.rb and # test_puma_localhost_authority.rb if Puma::HAS_SSL - require "puma/events" - class SSLEventsHelper < ::Puma::Events + require 'puma/log_writer' + class SSLLogWriterHelper < ::Puma::LogWriter attr_accessor :addr, :cert, :error def ssl_error(error, ssl_socket) diff --git a/test/test_binder.rb b/test/test_binder.rb index c2fa42b8..d7bd83b4 100644 --- a/test/test_binder.rb +++ b/test/test_binder.rb @@ -13,8 +13,8 @@ class TestBinderBase < Minitest::Test include TmpPath def setup - @events = Puma::Events.strings - @binder = Puma::Binder.new(@events) + @log_writer = Puma::LogWriter.strings + @binder = Puma::Binder.new(@log_writer) end def teardown @@ -80,14 +80,14 @@ class TestBinder < TestBinderBase end def test_localhost_addresses_dont_alter_listeners_for_tcp_addresses - @binder.parse ["tcp://localhost:0"], @events + @binder.parse ["tcp://localhost:0"], @log_writer assert_empty @binder.listeners end def test_home_alters_listeners_for_tcp_addresses port = UniquePort.call - @binder.parse ["tcp://127.0.0.1:#{port}"], @events + @binder.parse ["tcp://127.0.0.1:#{port}"], @log_writer assert_equal "tcp://127.0.0.1:#{port}", @binder.listeners[0][0] assert_kind_of TCPServer, @binder.listeners[0][1] @@ -96,14 +96,14 @@ class TestBinder < TestBinderBase def test_connected_ports ports = (1..3).map { |_| UniquePort.call } - @binder.parse(ports.map { |p| "tcp://localhost:#{p}" }, @events) + @binder.parse(ports.map { |p| "tcp://localhost:#{p}" }, @log_writer) assert_equal ports, @binder.connected_ports end def test_localhost_addresses_dont_alter_listeners_for_ssl_addresses skip_unless :ssl - @binder.parse ["ssl://localhost:0?#{ssl_query}"], @events + @binder.parse ["ssl://localhost:0?#{ssl_query}"], @log_writer assert_empty @binder.listeners end @@ -111,16 +111,16 @@ class TestBinder < TestBinderBase def test_home_alters_listeners_for_ssl_addresses skip_unless :ssl port = UniquePort.call - @binder.parse ["ssl://127.0.0.1:#{port}?#{ssl_query}"], @events + @binder.parse ["ssl://127.0.0.1:#{port}?#{ssl_query}"], @log_writer assert_equal "ssl://127.0.0.1:#{port}?#{ssl_query}", @binder.listeners[0][0] assert_kind_of TCPServer, @binder.listeners[0][1] end def test_correct_zero_port - @binder.parse ["tcp://localhost:0"], @events + @binder.parse ["tcp://localhost:0"], @log_writer - m = %r!http://127.0.0.1:(\d+)!.match(@events.stdout.string) + m = %r!http://127.0.0.1:(\d+)!.match(@log_writer.stdout.string) port = m[1].to_i refute_equal 0, port @@ -131,30 +131,30 @@ class TestBinder < TestBinderBase ssl_regex = %r!ssl://127.0.0.1:(\d+)! - @binder.parse ["ssl://localhost:0?#{ssl_query}"], @events + @binder.parse ["ssl://localhost:0?#{ssl_query}"], @log_writer - port = ssl_regex.match(@events.stdout.string)[1].to_i + port = ssl_regex.match(@log_writer.stdout.string)[1].to_i refute_equal 0, port end def test_logs_all_localhost_bindings - @binder.parse ["tcp://localhost:0"], @events + @binder.parse ["tcp://localhost:0"], @log_writer - assert_match %r!http://127.0.0.1:(\d+)!, @events.stdout.string + assert_match %r!http://127.0.0.1:(\d+)!, @log_writer.stdout.string if Socket.ip_address_list.any? {|i| i.ipv6_loopback? } - assert_match %r!http://\[::1\]:(\d+)!, @events.stdout.string + assert_match %r!http://\[::1\]:(\d+)!, @log_writer.stdout.string end end def test_logs_all_localhost_bindings_ssl skip_unless :ssl - @binder.parse ["ssl://localhost:0?#{ssl_query}"], @events + @binder.parse ["ssl://localhost:0?#{ssl_query}"], @log_writer - assert_match %r!ssl://127.0.0.1:(\d+)!, @events.stdout.string + assert_match %r!ssl://127.0.0.1:(\d+)!, @log_writer.stdout.string if Socket.ip_address_list.any? {|i| i.ipv6_loopback? } - assert_match %r!ssl://\[::1\]:(\d+)!, @events.stdout.string + assert_match %r!ssl://\[::1\]:(\d+)!, @log_writer.stdout.string end end @@ -176,9 +176,9 @@ class TestBinder < TestBinderBase unix_path = tmp_path('.sock') File.open(unix_path, mode: 'wb') { |f| f.puts 'pre existing' } - @binder.parse ["unix://#{unix_path}"], @events + @binder.parse ["unix://#{unix_path}"], @log_writer - assert_match %r!unix://#{unix_path}!, @events.stdout.string + assert_match %r!unix://#{unix_path}!, @log_writer.stdout.string refute_includes @binder.unix_paths, unix_path @@ -194,7 +194,7 @@ class TestBinder < TestBinderBase def test_binder_parses_nil_low_latency skip_if :jruby - @binder.parse ["tcp://0.0.0.0:0?low_latency"], @events + @binder.parse ["tcp://0.0.0.0:0?low_latency"], @log_writer socket = @binder.listeners.first.last @@ -203,7 +203,7 @@ class TestBinder < TestBinderBase def test_binder_parses_true_low_latency skip_if :jruby - @binder.parse ["tcp://0.0.0.0:0?low_latency=true"], @events + @binder.parse ["tcp://0.0.0.0:0?low_latency=true"], @log_writer socket = @binder.listeners.first.last @@ -212,7 +212,7 @@ class TestBinder < TestBinderBase def test_binder_parses_false_low_latency skip_if :jruby - @binder.parse ["tcp://0.0.0.0:0?low_latency=false"], @events + @binder.parse ["tcp://0.0.0.0:0?low_latency=false"], @log_writer socket = @binder.listeners.first.last @@ -221,21 +221,21 @@ class TestBinder < TestBinderBase def test_binder_parses_tlsv1_disabled skip_unless :ssl - @binder.parse ["ssl://0.0.0.0:0?#{ssl_query}&no_tlsv1=true"], @events + @binder.parse ["ssl://0.0.0.0:0?#{ssl_query}&no_tlsv1=true"], @log_writer assert ssl_context_for_binder.no_tlsv1 end def test_binder_parses_tlsv1_enabled skip_unless :ssl - @binder.parse ["ssl://0.0.0.0:0?#{ssl_query}&no_tlsv1=false"], @events + @binder.parse ["ssl://0.0.0.0:0?#{ssl_query}&no_tlsv1=false"], @log_writer refute ssl_context_for_binder.no_tlsv1 end def test_binder_parses_tlsv1_tlsv1_1_unspecified_defaults_to_enabled skip_unless :ssl - @binder.parse ["ssl://0.0.0.0:0?#{ssl_query}"], @events + @binder.parse ["ssl://0.0.0.0:0?#{ssl_query}"], @log_writer refute ssl_context_for_binder.no_tlsv1 refute ssl_context_for_binder.no_tlsv1_1 @@ -243,21 +243,21 @@ class TestBinder < TestBinderBase def test_binder_parses_tlsv1_1_disabled skip_unless :ssl - @binder.parse ["ssl://0.0.0.0:0?#{ssl_query}&no_tlsv1_1=true"], @events + @binder.parse ["ssl://0.0.0.0:0?#{ssl_query}&no_tlsv1_1=true"], @log_writer assert ssl_context_for_binder.no_tlsv1_1 end def test_binder_parses_tlsv1_1_enabled skip_unless :ssl - @binder.parse ["ssl://0.0.0.0:0?#{ssl_query}&no_tlsv1_1=false"], @events + @binder.parse ["ssl://0.0.0.0:0?#{ssl_query}&no_tlsv1_1=false"], @log_writer refute ssl_context_for_binder.no_tlsv1_1 end def test_env_contains_protoenv skip_unless :ssl - @binder.parse ["ssl://localhost:0?#{ssl_query}"], @events + @binder.parse ["ssl://localhost:0?#{ssl_query}"], @log_writer env_hash = @binder.envs[@binder.ios.first] @@ -268,11 +268,11 @@ class TestBinder < TestBinderBase def test_env_contains_stderr skip_unless :ssl - @binder.parse ["ssl://localhost:0?#{ssl_query}"], @events + @binder.parse ["ssl://localhost:0?#{ssl_query}"], @log_writer env_hash = @binder.envs[@binder.ios.first] - assert_equal @events.stderr, env_hash["rack.errors"] + assert_equal @log_writer.stderr, env_hash["rack.errors"] end def test_ssl_binder_sets_backlog @@ -287,7 +287,7 @@ class TestBinder < TestBinderBase end TCPServer.stub(:new, tcp_server) do - @binder.parse ["ssl://#{host}:#{port}?#{ssl_query}&backlog=2048"], @events + @binder.parse ["ssl://#{host}:#{port}?#{ssl_query}&backlog=2048"], @log_writer end assert_equal 2048, Thread.current[:backlog] @@ -304,7 +304,7 @@ class TestBinder < TestBinderBase end def test_redirects_for_restart_creates_a_hash - @binder.parse ["tcp://127.0.0.1:0"], @events + @binder.parse ["tcp://127.0.0.1:0"], @log_writer result = @binder.redirects_for_restart ios = @binder.listeners.map { |_l, io| io.to_i } @@ -314,7 +314,7 @@ class TestBinder < TestBinderBase end def test_redirects_for_restart_env - @binder.parse ["tcp://127.0.0.1:0"], @events + @binder.parse ["tcp://127.0.0.1:0"], @log_writer result = @binder.redirects_for_restart_env @@ -324,7 +324,7 @@ class TestBinder < TestBinderBase end def test_close_listeners_closes_ios - @binder.parse ["tcp://127.0.0.1:#{UniquePort.call}"], @events + @binder.parse ["tcp://127.0.0.1:#{UniquePort.call}"], @log_writer refute @binder.listeners.any? { |_l, io| io.closed? } @@ -334,7 +334,7 @@ class TestBinder < TestBinderBase end def test_close_listeners_closes_ios_unless_closed? - @binder.parse ["tcp://127.0.0.1:0"], @events + @binder.parse ["tcp://127.0.0.1:0"], @log_writer bomb = @binder.listeners.first[1] bomb.close @@ -351,7 +351,7 @@ class TestBinder < TestBinderBase skip_unless :unix unix_path = tmp_path('.sock') - @binder.parse ["unix://#{unix_path}"], @events + @binder.parse ["unix://#{unix_path}"], @log_writer assert File.socket?(unix_path) @binder.close_listeners @@ -359,7 +359,7 @@ class TestBinder < TestBinderBase end def test_import_from_env_listen_inherit - @binder.parse ["tcp://127.0.0.1:0"], @events + @binder.parse ["tcp://127.0.0.1:0"], @log_writer removals = @binder.create_inherited_fds(@binder.redirects_for_restart_env) @binder.listeners.each do |l, io| @@ -399,7 +399,7 @@ class TestBinder < TestBinderBase end def test_rack_multithread_default_configuration - binder = Puma::Binder.new(@events) + binder = Puma::Binder.new(@log_writer) assert binder.proto_env["rack.multithread"] end @@ -407,13 +407,13 @@ class TestBinder < TestBinderBase def test_rack_multithread_custom_configuration conf = Puma::Configuration.new(max_threads: 1) - binder = Puma::Binder.new(@events, conf) + binder = Puma::Binder.new(@log_writer, conf) refute binder.proto_env["rack.multithread"] end def test_rack_multiprocess_default_configuration - binder = Puma::Binder.new(@events) + binder = Puma::Binder.new(@log_writer) refute binder.proto_env["rack.multiprocess"] end @@ -421,7 +421,7 @@ class TestBinder < TestBinderBase def test_rack_multiprocess_custom_configuration conf = Puma::Configuration.new(workers: 1) - binder = Puma::Binder.new(@events, conf) + binder = Puma::Binder.new(@log_writer, conf) assert binder.proto_env["rack.multiprocess"] end @@ -430,7 +430,7 @@ class TestBinder < TestBinderBase def assert_activates_sockets(path: nil, port: nil, url: nil, sock: nil) hash = { "LISTEN_FDS" => 1, "LISTEN_PID" => $$ } - @events.instance_variable_set(:@debug, true) + @log_writer.instance_variable_set(:@debug, true) @binder.instance_variable_set(:@sock_fd, sock.fileno) def @binder.socket_activation_fd(int); @sock_fd; end @@ -440,7 +440,7 @@ class TestBinder < TestBinderBase ary = path ? [:unix, path] : [:tcp, url, port] assert_kind_of TCPServer, @binder.activated_sockets[ary] - assert_match "Registered #{ary.join(":")} for activation from LISTEN_FDS", @events.stdout.string + assert_match "Registered #{ary.join(":")} for activation from LISTEN_FDS", @log_writer.stdout.string assert_equal ["LISTEN_FDS", "LISTEN_PID"], @result end @@ -461,8 +461,8 @@ class TestBinder < TestBinderBase tested_paths = [prepared_paths[order[0]], prepared_paths[order[1]]] - @binder.parse tested_paths, @events - stdout = @events.stdout.string + @binder.parse tested_paths, @log_writer + stdout = @log_writer.stdout.string order.each do |prot| assert_match expected_logs[prot], stdout @@ -479,7 +479,7 @@ class TestBinderJRuby < TestBinderBase keystore = File.expand_path "../../examples/puma/keystore.jks", __FILE__ ssl_cipher_list = "TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" - @binder.parse ["ssl://0.0.0.0:8080?#{ssl_query}"], @events + @binder.parse ["ssl://0.0.0.0:8080?#{ssl_query}"], @log_writer assert_equal keystore, ssl_context_for_binder.keystore assert_equal ssl_cipher_list, ssl_context_for_binder.ssl_cipher_list @@ -492,7 +492,7 @@ class TestBinderMRI < TestBinderBase ssl_cipher_filter = "AES@STRENGTH" - @binder.parse ["ssl://0.0.0.0?#{ssl_query}&ssl_cipher_filter=#{ssl_cipher_filter}"], @events + @binder.parse ["ssl://0.0.0.0?#{ssl_query}&ssl_cipher_filter=#{ssl_cipher_filter}"], @log_writer assert_equal ssl_cipher_filter, ssl_context_for_binder.ssl_cipher_filter end @@ -502,7 +502,7 @@ class TestBinderMRI < TestBinderBase input = "&verification_flags=TRUSTED_FIRST" - @binder.parse ["ssl://0.0.0.0?#{ssl_query}#{input}"], @events + @binder.parse ["ssl://0.0.0.0?#{ssl_query}#{input}"], @log_writer assert_equal 0x8000, ssl_context_for_binder.verification_flags end @@ -512,7 +512,7 @@ class TestBinderMRI < TestBinderBase input = "&verification_flags=TRUSTED_FIRST,NO_CHECK_TIME" - @binder.parse ["ssl://0.0.0.0?#{ssl_query}#{input}"], @events + @binder.parse ["ssl://0.0.0.0?#{ssl_query}#{input}"], @log_writer assert_equal 0x8000 | 0x200000, ssl_context_for_binder.verification_flags end diff --git a/test/test_bundle_pruner.rb b/test/test_bundle_pruner.rb index 19d7e651..2ed8eb82 100644 --- a/test/test_bundle_pruner.rb +++ b/test/test_bundle_pruner.rb @@ -52,6 +52,6 @@ class TestBundlePruner < Minitest::Test private def bundle_pruner(original_argv = nil, extra_runtime_dependencies = nil) - @bundle_pruner ||= Puma::Launcher::BundlePruner.new(original_argv, extra_runtime_dependencies, Puma::Events.null) + @bundle_pruner ||= Puma::Launcher::BundlePruner.new(original_argv, extra_runtime_dependencies, Puma::LogWriter.null) end end diff --git a/test/test_busy_worker.rb b/test/test_busy_worker.rb index e5321369..ea46391e 100644 --- a/test/test_busy_worker.rb +++ b/test/test_busy_worker.rb @@ -53,7 +53,7 @@ class TestBusyWorker < Minitest::Test end end - @server = Puma::Server.new request_handler, Puma::Events.strings, **options + @server = Puma::Server.new request_handler, Puma::LogWriter.strings, Puma::Events.new, **options @server.min_threads = options[:min_threads] || 0 @server.max_threads = options[:max_threads] || 10 @port = (@server.add_tcp_listener '127.0.0.1', 0).addr[1] diff --git a/test/test_cli.rb b/test/test_cli.rb index 09670705..ffe32401 100644 --- a/test/test_cli.rb +++ b/test/test_cli.rb @@ -21,7 +21,9 @@ class TestCLI < Minitest::Test @wait, @ready = IO.pipe - @events = Puma::Events.strings + @log_writer = Puma::LogWriter.strings + + @events = Puma::Events.new @events.on_booted { @ready << "!" } end @@ -47,7 +49,7 @@ class TestCLI < Minitest::Test cli = Puma::CLI.new ["-b", "tcp://127.0.0.1:0", "--control-url", url, "--control-token", "", - "test/rackup/lobster.ru"], @events + "test/rackup/lobster.ru"], @log_writer, @events t = Thread.new do cli.run @@ -82,7 +84,7 @@ class TestCLI < Minitest::Test cli = Puma::CLI.new ["-b", "tcp://127.0.0.1:0", "--control-url", control_url, "--control-token", token, - "test/rackup/lobster.ru"], @events + "test/rackup/lobster.ru"], @log_writer, @events t = Thread.new do cli.run @@ -118,7 +120,7 @@ class TestCLI < Minitest::Test "-w", "2", "--control-url", url, "--control-token", "", - "test/rackup/lobster.ru"], @events + "test/rackup/lobster.ru"], @log_writer, @events # without this, Minitest.after_run will trigger on this test ? $debugging_hold = true @@ -150,8 +152,8 @@ class TestCLI < Minitest::Test done = nil until done - @events.stdout.rewind - log = @events.stdout.readlines.join '' + @log_writer.stdout.rewind + log = @log_writer.stdout.readlines.join '' done = log[/ - Goodbye!/] end @@ -166,7 +168,7 @@ class TestCLI < Minitest::Test cli = Puma::CLI.new ["-b", "unix://#{@tmp_path2}", "--control-url", url, "--control-token", "", - "test/rackup/lobster.ru"], @events + "test/rackup/lobster.ru"], @log_writer, @events t = Thread.new { cli.run } @@ -193,7 +195,7 @@ class TestCLI < Minitest::Test cli = Puma::CLI.new ["-b", "unix://#{@tmp_path2}", "--control-url", url, "--control-token", "", - "test/rackup/lobster.ru"], @events + "test/rackup/lobster.ru"], @log_writer, @events t = Thread.new { cli.run } @@ -217,7 +219,7 @@ class TestCLI < Minitest::Test cli = Puma::CLI.new ["-b", "tcp://127.0.0.1:#{tcp}", "--control-url", url, "--control-token", "", - "test/rackup/lobster.ru"], @events + "test/rackup/lobster.ru"], @log_writer, @events t = Thread.new do cli.run @@ -258,7 +260,7 @@ class TestCLI < Minitest::Test cli = Puma::CLI.new ["-b", "unix://#{@tmp_path2}", "--control-url", url, "--control-token", "", - "test/rackup/lobster.ru"], @events + "test/rackup/lobster.ru"], @log_writer, @events t = Thread.new { cli.run } @@ -279,7 +281,7 @@ class TestCLI < Minitest::Test cli = Puma::CLI.new ["-b", uri, "--control-url", cntl, "--control-token", "", - "test/rackup/lobster.ru"], @events + "test/rackup/lobster.ru"], @log_writer, @events t = Thread.new do cli.run @@ -384,28 +386,28 @@ class TestCLI < Minitest::Test def test_log_formatter_default_single cli = Puma::CLI.new [ ] - assert_instance_of Puma::Events::DefaultFormatter, cli.launcher.events.formatter + assert_instance_of Puma::LogWriter::DefaultFormatter, cli.launcher.log_writer.formatter end def test_log_formatter_default_clustered skip_unless :fork cli = Puma::CLI.new [ "-w 2" ] - assert_instance_of Puma::Events::PidFormatter, cli.launcher.events.formatter + assert_instance_of Puma::LogWriter::PidFormatter, cli.launcher.log_writer.formatter end def test_log_formatter_custom_single cli = Puma::CLI.new [ "--config", "test/config/custom_log_formatter.rb" ] - assert_instance_of Proc, cli.launcher.events.formatter - assert_match(/^\[.*\] \[.*\] .*: test$/, cli.launcher.events.format('test')) + assert_instance_of Proc, cli.launcher.log_writer.formatter + assert_match(/^\[.*\] \[.*\] .*: test$/, cli.launcher.log_writer.format('test')) end def test_log_formatter_custom_clustered skip_unless :fork cli = Puma::CLI.new [ "--config", "test/config/custom_log_formatter.rb", "-w 2" ] - assert_instance_of Proc, cli.launcher.events.formatter - assert_match(/^\[.*\] \[.*\] .*: test$/, cli.launcher.events.format('test')) + assert_instance_of Proc, cli.launcher.log_writer.formatter + assert_match(/^\[.*\] \[.*\] .*: test$/, cli.launcher.log_writer.format('test')) end def test_state @@ -480,10 +482,10 @@ class TestCLI < Minitest::Test cli = Puma::CLI.new ['--silent'] cli.send(:setup_options) - events = cli.instance_variable_get(:@events) + log_writer = cli.instance_variable_get(:@log_writer) - assert_equal events.class, Puma::Events.null.class - assert_equal events.stdout.class, Puma::NullIO - assert_equal events.stderr, $stderr + assert_equal log_writer.class, Puma::LogWriter.null.class + assert_equal log_writer.stdout.class, Puma::NullIO + assert_equal log_writer.stderr, $stderr end end diff --git a/test/test_config.rb b/test/test_config.rb index d2ced63f..16873f0b 100644 --- a/test/test_config.rb +++ b/test/test_config.rb @@ -4,7 +4,7 @@ require_relative "helper" require_relative "helpers/config_file" require "puma/configuration" -require 'puma/events' +require 'puma/log_writer' class TestConfigFile < TestConfigFileBase parallelize_me! @@ -373,11 +373,11 @@ class TestConfigFile < TestConfigFileBase end end conf.load - events = Puma::Events.strings + log_writer = Puma::LogWriter.strings - conf.run_hooks :on_restart, 'ARG', events + conf.run_hooks(:on_restart, 'ARG', log_writer) expected = /WARNING hook on_restart failed with exception \(RuntimeError\) Error from hook/ - assert_match expected, events.stdout.string + assert_match expected, log_writer.stdout.string end def test_config_does_not_load_workers_by_default @@ -419,7 +419,7 @@ class TestConfigFile < TestConfigFileBase messages << "#{hook_name} is called with #{a}" } - conf.run_hooks hook_name, 'ARG', Puma::Events.strings + conf.run_hooks(hook_name, 'ARG', Puma::LogWriter.strings) assert_equal messages, ["#{hook_name} is called with ARG"] # test multiple @@ -435,7 +435,7 @@ class TestConfigFile < TestConfigFileBase end conf.load - conf.run_hooks hook_name, 'ARG', Puma::Events.strings + conf.run_hooks(hook_name, 'ARG', Puma::LogWriter.strings) assert_equal messages, ["#{hook_name} is called with ARG one time", "#{hook_name} is called with ARG a second time"] end end diff --git a/test/test_events.rb b/test/test_events.rb index f4df5fb0..4bf8fd83 100644 --- a/test/test_events.rb +++ b/test/test_events.rb @@ -2,41 +2,10 @@ require 'puma/events' require_relative "helper" class TestEvents < Minitest::Test - def test_null - events = Puma::Events.null - - assert_instance_of Puma::NullIO, events.stdout - assert_instance_of Puma::NullIO, events.stderr - assert_equal events.stdout, events.stderr - end - - def test_strings - events = Puma::Events.strings - - assert_instance_of StringIO, events.stdout - assert_instance_of StringIO, events.stderr - end - - def test_stdio - events = Puma::Events.stdio - - assert_equal STDOUT, events.stdout - assert_equal STDERR, events.stderr - end - - def test_stdio_respects_sync - events = Puma::Events.stdio - - assert_equal STDOUT.sync, events.stdout.sync - assert_equal STDERR.sync, events.stderr.sync - assert_equal STDOUT, events.stdout - assert_equal STDERR, events.stderr - end - def test_register_callback_with_block res = false - events = Puma::Events.null + events = Puma::Events.new events.register(:exec) { res = true } @@ -56,7 +25,7 @@ class TestEvents < Minitest::Test @res = true end - events = Puma::Events.null + events = Puma::Events.new events.register(:exec, obj) @@ -68,7 +37,7 @@ class TestEvents < Minitest::Test def test_fire_callback_with_multiple_arguments res = [] - events = Puma::Events.null + events = Puma::Events.new events.register(:exec) { |*args| res.concat(args) } @@ -80,7 +49,7 @@ class TestEvents < Minitest::Test def test_on_booted_callback res = false - events = Puma::Events.null + events = Puma::Events.new events.on_booted { res = true } @@ -88,151 +57,4 @@ class TestEvents < Minitest::Test assert res end - - def test_log_writes_to_stdout - out, _ = capture_io do - Puma::Events.stdio.log("ready") - end - - assert_equal "ready\n", out - end - - def test_null_log_does_nothing - out, _ = capture_io do - Puma::Events.null.log("ready") - end - - assert_equal "", out - end - - def test_write_writes_to_stdout - out, _ = capture_io do - Puma::Events.stdio.write("ready") - end - - assert_equal "ready", out - end - - def test_debug_writes_to_stdout_if_env_is_present - original_debug, ENV["PUMA_DEBUG"] = ENV["PUMA_DEBUG"], "1" - - out, _ = capture_io do - Puma::Events.stdio.debug("ready") - end - - assert_equal "% ready\n", out - ensure - ENV["PUMA_DEBUG"] = original_debug - end - - def test_debug_not_write_to_stdout_if_env_is_not_present - out, _ = capture_io do - Puma::Events.stdio.debug("ready") - end - - assert_empty out - end - - def test_error_writes_to_stderr_and_exits - did_exit = false - - _, err = capture_io do - begin - Puma::Events.stdio.error("interrupted") - rescue SystemExit - did_exit = true - ensure - assert did_exit - end - end - - assert_match %r!ERROR: interrupted!, err - end - - def test_pid_formatter - pid = Process.pid - - out, _ = capture_io do - events = Puma::Events.stdio - - events.formatter = Puma::Events::PidFormatter.new - - events.write("ready") - end - - assert_equal "[#{ pid }] ready", out - end - - def test_custom_log_formatter - custom_formatter = proc { |str| "-> #{ str }" } - - out, _ = capture_io do - events = Puma::Events.stdio - - events.formatter = custom_formatter - - events.write("ready") - end - - assert_equal "-> ready", out - end - - def test_parse_error - port = 0 - host = "127.0.0.1" - app = proc { |env| [200, {"Content-Type" => "plain/text"}, ["hello\n"]] } - events = Puma::Events.strings - server = Puma::Server.new app, events - - port = (server.add_tcp_listener host, 0).addr[1] - server.run - - sock = TCPSocket.new host, port - path = "/" - params = "a"*1024*10 - - sock << "GET #{path}?a=#{params} HTTP/1.1\r\nConnection: close\r\n\r\n" - sock.read - sleep 0.1 # important so that the previous data is sent as a packet - assert_match %r!HTTP parse error, malformed request!, events.stderr.string - assert_match %r!\("GET #{path}" - \(-\)\)!, events.stderr.string - ensure - sock.close if sock && !sock.closed? - server.stop true - end - - # test_puma_server_ssl.rb checks that ssl errors are raised correctly, - # but it mocks the actual error code. This test the code, but it will - # break if the logged message changes - def test_ssl_error - events = Puma::Events.strings - - ssl_mock = -> (addr, subj) { - obj = Object.new - obj.define_singleton_method(:peeraddr) { addr } - if subj - cert = Object.new - cert.define_singleton_method(:subject) { subj } - obj.define_singleton_method(:peercert) { cert } - else - obj.define_singleton_method(:peercert) { nil } - end - obj - } - - events.ssl_error OpenSSL::SSL::SSLError, ssl_mock.call(['127.0.0.1'], 'test_cert') - error = events.stderr.string - assert_includes error, "SSL error" - assert_includes error, "peer: 127.0.0.1" - assert_includes error, "cert: test_cert" - - events.stderr.string = '' - - events.ssl_error OpenSSL::SSL::SSLError, ssl_mock.call(nil, nil) - error = events.stderr.string - assert_includes error, "SSL error" - assert_includes error, "peer: " - assert_includes error, "cert: :" - - end if ::Puma::HAS_SSL end diff --git a/test/test_launcher.rb b/test/test_launcher.rb index 30abe6b7..573dedd1 100644 --- a/test/test_launcher.rb +++ b/test/test_launcher.rb @@ -2,7 +2,7 @@ require_relative "helper" require_relative "helpers/tmp_path" require "puma/configuration" -require 'puma/events' +require 'puma/log_writer' class TestLauncher < Minitest::Test include TmpPath @@ -112,17 +112,17 @@ class TestLauncher < Minitest::Test def test_log_config_enabled ENV['PUMA_LOG_CONFIG'] = "1" - assert_match(/Configuration:/, launcher.events.stdout.string) + assert_match(/Configuration:/, launcher.log_writer.stdout.string) launcher.config.final_options.each do |config_key, _value| - assert_match(/#{config_key}/, launcher.events.stdout.string) + assert_match(/#{config_key}/, launcher.log_writer.stdout.string) end ENV.delete('PUMA_LOG_CONFIG') end def test_log_config_disabled - refute_match(/Configuration:/, launcher.events.stdout.string) + refute_match(/Configuration:/, launcher.log_writer.stdout.string) end def test_fire_on_stopped @@ -147,11 +147,11 @@ class TestLauncher < Minitest::Test private - def events - @events ||= Puma::Events.strings + def log_writer + @log_writer ||= Puma::LogWriter.strings end - def launcher(config = Puma::Configuration.new, evts = events) - @launcher ||= Puma::Launcher.new(config, events: evts) + def launcher(config = Puma::Configuration.new, lw = log_writer) + @launcher ||= Puma::Launcher.new(config, log_writer: lw) end end diff --git a/test/test_log_writer.rb b/test/test_log_writer.rb new file mode 100644 index 00000000..0b9502b8 --- /dev/null +++ b/test/test_log_writer.rb @@ -0,0 +1,181 @@ +require 'puma/log_writer' +require_relative "helper" + +class TestLogWriter < Minitest::Test + def test_null + log_writer = Puma::LogWriter.null + + assert_instance_of Puma::NullIO, log_writer.stdout + assert_instance_of Puma::NullIO, log_writer.stderr + assert_equal log_writer.stdout, log_writer.stderr + end + + def test_strings + log_writer = Puma::LogWriter.strings + + assert_instance_of StringIO, log_writer.stdout + assert_instance_of StringIO, log_writer.stderr + end + + def test_stdio + log_writer = Puma::LogWriter.stdio + + assert_equal STDOUT, log_writer.stdout + assert_equal STDERR, log_writer.stderr + end + + def test_stdio_respects_sync + log_writer = Puma::LogWriter.stdio + + assert_equal STDOUT.sync, log_writer.stdout.sync + assert_equal STDERR.sync, log_writer.stderr.sync + assert_equal STDOUT, log_writer.stdout + assert_equal STDERR, log_writer.stderr + end + + def test_log_writes_to_stdout + out, _ = capture_io do + Puma::LogWriter.stdio.log("ready") + end + + assert_equal "ready\n", out + end + + def test_null_log_does_nothing + out, _ = capture_io do + Puma::LogWriter.null.log("ready") + end + + assert_equal "", out + end + + def test_write_writes_to_stdout + out, _ = capture_io do + Puma::LogWriter.stdio.write("ready") + end + + assert_equal "ready", out + end + + def test_debug_writes_to_stdout_if_env_is_present + original_debug, ENV["PUMA_DEBUG"] = ENV["PUMA_DEBUG"], "1" + + out, _ = capture_io do + Puma::LogWriter.stdio.debug("ready") + end + + assert_equal "% ready\n", out + ensure + ENV["PUMA_DEBUG"] = original_debug + end + + def test_debug_not_write_to_stdout_if_env_is_not_present + out, _ = capture_io do + Puma::LogWriter.stdio.debug("ready") + end + + assert_empty out + end + + def test_error_writes_to_stderr_and_exits + did_exit = false + + _, err = capture_io do + begin + Puma::LogWriter.stdio.error("interrupted") + rescue SystemExit + did_exit = true + ensure + assert did_exit + end + end + + assert_match %r!ERROR: interrupted!, err + end + + def test_pid_formatter + pid = Process.pid + + out, _ = capture_io do + log_writer = Puma::LogWriter.stdio + + log_writer.formatter = Puma::LogWriter::PidFormatter.new + + log_writer.write("ready") + end + + assert_equal "[#{ pid }] ready", out + end + + def test_custom_log_formatter + custom_formatter = proc { |str| "-> #{ str }" } + + out, _ = capture_io do + log_writer = Puma::LogWriter.stdio + + log_writer.formatter = custom_formatter + + log_writer.write("ready") + end + + assert_equal "-> ready", out + end + + def test_parse_error + app = proc { |_env| [200, {"Content-Type" => "plain/text"}, ["hello\n"]] } + log_writer = Puma::LogWriter.strings + server = Puma::Server.new app, log_writer + + host = '127.0.0.1' + port = (server.add_tcp_listener host, 0).addr[1] + server.run + + sock = TCPSocket.new host, port + path = "/" + params = "a"*1024*10 + + sock << "GET #{path}?a=#{params} HTTP/1.1\r\nConnection: close\r\n\r\n" + sock.read + sleep 0.1 # important so that the previous data is sent as a packet + assert_match %r!HTTP parse error, malformed request!, log_writer.stderr.string + assert_match %r!\("GET #{path}" - \(-\)\)!, log_writer.stderr.string + ensure + sock.close if sock && !sock.closed? + server.stop true + end + + # test_puma_server_ssl.rb checks that ssl errors are raised correctly, + # but it mocks the actual error code. This test the code, but it will + # break if the logged message changes + def test_ssl_error + log_writer = Puma::LogWriter.strings + + ssl_mock = -> (addr, subj) { + obj = Object.new + obj.define_singleton_method(:peeraddr) { addr } + if subj + cert = Object.new + cert.define_singleton_method(:subject) { subj } + obj.define_singleton_method(:peercert) { cert } + else + obj.define_singleton_method(:peercert) { nil } + end + obj + } + + log_writer.ssl_error OpenSSL::SSL::SSLError, ssl_mock.call(['127.0.0.1'], 'test_cert') + error = log_writer.stderr.string + assert_includes error, "SSL error" + assert_includes error, "peer: 127.0.0.1" + assert_includes error, "cert: test_cert" + + log_writer.stderr.string = '' + + log_writer.ssl_error OpenSSL::SSL::SSLError, ssl_mock.call(nil, nil) + error = log_writer.stderr.string + assert_includes error, "SSL error" + assert_includes error, "peer: " + assert_includes error, "cert: :" + + end if ::Puma::HAS_SSL +end diff --git a/test/test_out_of_band_server.rb b/test/test_out_of_band_server.rb index 27eec9b7..c0ca7d4a 100644 --- a/test/test_out_of_band_server.rb +++ b/test/test_out_of_band_server.rb @@ -59,7 +59,7 @@ class TestOutOfBandServer < Minitest::Test [200, {}, [""]] end - @server = Puma::Server.new app, Puma::Events.strings, out_of_band: [oob], **options + @server = Puma::Server.new app, Puma::LogWriter.strings, Puma::Events.new, out_of_band: [oob], **options @server.min_threads = options[:min_threads] || 1 @server.max_threads = options[:max_threads] || 1 @port = (@server.add_tcp_listener '127.0.0.1', 0).addr[1] diff --git a/test/test_puma_localhost_authority.rb b/test/test_puma_localhost_authority.rb index 8599980b..f40c4ec1 100644 --- a/test/test_puma_localhost_authority.rb +++ b/test/test_puma_localhost_authority.rb @@ -30,8 +30,8 @@ class TestPumaLocalhostAuthority < Minitest::Test @host = "localhost" app = lambda { |env| [200, {}, [env['rack.url_scheme']]] } - @events = SSLEventsHelper.new STDOUT, STDERR - @server = Puma::Server.new app, @events + @log_writer = SSLLogWriterHelper.new STDOUT, STDERR + @server = Puma::Server.new app, @log_writer @server.app = app @server.add_ssl_listener @host, 0,nil @http = Net::HTTP.new @host, @server.connected_ports[0] @@ -61,9 +61,9 @@ class TestPumaSSLLocalhostAuthority < Minitest::Test app = lambda { |env| [200, {}, [env['rack.url_scheme']]] } - @events = SSLEventsHelper.new STDOUT, STDERR + @log_writer = SSLLogWriterHelper.new STDOUT, STDERR - @server = Puma::Server.new app, @events + @server = Puma::Server.new app, @log_writer @server.app = app @server.add_ssl_listener @host, 0,nil diff --git a/test/test_puma_server.rb b/test/test_puma_server.rb index 4909f268..f89490ec 100644 --- a/test/test_puma_server.rb +++ b/test/test_puma_server.rb @@ -14,8 +14,9 @@ class TestPumaServer < Minitest::Test @app = ->(env) { [200, {}, [env['rack.url_scheme']]] } - @events = Puma::Events.strings - @server = Puma::Server.new @app, @events + @log_writer = Puma::LogWriter.strings + @events = Puma::Events.new + @server = Puma::Server.new @app, @log_writer, @events end def teardown @@ -24,7 +25,7 @@ class TestPumaServer < Minitest::Test end def server_run(**options, &block) - @server = Puma::Server.new block || @app, @events, options + @server = Puma::Server.new block || @app, @log_writer, @events, options @port = (@server.add_tcp_listener @host, 0).addr[1] @server.run sleep 0.15 if Puma.jruby? @@ -296,7 +297,7 @@ EOF sleep 0.1 # Expect no errors in stderr - assert @events.stderr.pos.zero?, "Server didn't swallow the connection error" + assert @log_writer.stderr.pos.zero?, "Server didn't swallow the connection error" end def test_early_hints_is_off_by_default @@ -341,7 +342,7 @@ EOF new_connection.close # Make a connection and close without writing @server.stop(true) - stderr = @events.stderr.string + stderr = @log_writer.stderr.string assert stderr.empty?, "Expected stderr from server to be empty but it was #{stderr.inspect}" end @@ -361,7 +362,7 @@ EOF def test_lowlevel_error_message skip_if :windows - @server = Puma::Server.new @app, @events, {:force_shutdown_after => 2} + @server = Puma::Server.new @app, @log_writer, @events, {:force_shutdown_after => 2} server_run do if TestSkips::TRUFFLE @@ -508,7 +509,7 @@ EOF end def test_no_timeout_after_data_received_no_queue - @server = Puma::Server.new @app, @events, queue_requests: false + @server = Puma::Server.new @app, @log_writer, @events, queue_requests: false test_no_timeout_after_data_received end @@ -1244,7 +1245,7 @@ EOF # System-resource errors such as EMFILE should not be silently swallowed by accept loop. def test_accept_emfile stub_accept_nonblock Errno::EMFILE.new('accept(2)') - refute_empty @events.stderr.string, "Expected EMFILE error not logged" + refute_empty @log_writer.stderr.string, "Expected EMFILE error not logged" end # Retryable errors such as ECONNABORTED should be silently swallowed by accept loop. @@ -1252,7 +1253,7 @@ EOF # Match Ruby #accept_nonblock implementation, ECONNABORTED error is extended by IO::WaitReadable. error = Errno::ECONNABORTED.new('accept(2) would block').tap {|e| e.extend IO::WaitReadable} stub_accept_nonblock(error) - assert_empty @events.stderr.string + assert_empty @log_writer.stderr.string end # see https://github.com/puma/puma/issues/2390 @@ -1260,7 +1261,7 @@ EOF # def test_client_quick_close_no_lowlevel_error_handler_call handler = ->(err, env, status) { - @events.stdout.write "LLEH #{err.message}" + @log_writer.stdout.write "LLEH #{err.message}" [500, {"Content-Type" => "application/json"}, ["{}\n"]] } @@ -1274,21 +1275,21 @@ EOF sock.close assert_match 'Hello World', resp sleep 0.5 - assert_empty @events.stdout.string + assert_empty @log_writer.stdout.string # valid req, close sock = TCPSocket.new @host, @port sock.syswrite "GET / HTTP/1.0\r\n\r\n" sock.close sleep 0.5 - assert_empty @events.stdout.string + assert_empty @log_writer.stdout.string # invalid req, close sock = TCPSocket.new @host, @port sock.syswrite "GET / HTTP" sock.close sleep 0.5 - assert_empty @events.stdout.string + assert_empty @log_writer.stdout.string end def test_idle_connections_closed_immediately_on_shutdown @@ -1325,7 +1326,7 @@ EOF def test_custom_io_selector backend = NIO::Selector.backends.first - @server = Puma::Server.new @app, @events, {:io_selector_backend => backend} + @server = Puma::Server.new @app, @log_writer, @events, {:io_selector_backend => backend} @server.run selector = @server.instance_variable_get(:@reactor).instance_variable_get(:@selector) @@ -1374,9 +1375,9 @@ EOF @port = UniquePort.call opts = { rack_url_scheme: 'user', binds: ["tcp://#{@host}:#{@port}"] } conf = Puma::Configuration.new(opts).tap(&:clamp) - @server = Puma::Server.new @app, @events, conf.options - @server.inherit_binder Puma::Binder.new(@events, conf) - @server.binder.parse conf.options[:binds], @events + @server = Puma::Server.new @app, @log_writer, @events, conf.options + @server.inherit_binder Puma::Binder.new(@log_writer, conf) + @server.binder.parse conf.options[:binds], @log_writer @server.run data = send_http_and_read "GET / HTTP/1.0\r\n\r\n" diff --git a/test/test_puma_server_ssl.rb b/test/test_puma_server_ssl.rb index 58fd6507..4d08d0ec 100644 --- a/test/test_puma_server_ssl.rb +++ b/test/test_puma_server_ssl.rb @@ -55,8 +55,8 @@ class TestPumaServerSSL < Minitest::Test yield ctx if block_given? - @events = SSLEventsHelper.new STDOUT, STDERR - @server = Puma::Server.new app, @events + @log_writer = SSLLogWriterHelper.new STDOUT, STDERR + @server = Puma::Server.new app, @log_writer @port = (@server.add_ssl_listener @host, 0, ctx).addr[1] @server.run @@ -148,7 +148,7 @@ class TestPumaServerSSL < Minitest::Test end unless Puma.jruby? msg = /wrong version number|no protocols available|version too low|unknown SSL method/ - assert_match(msg, @events.error.message) if @events.error + assert_match(msg, @log_writer.error.message) if @log_writer.error end end @@ -169,7 +169,7 @@ class TestPumaServerSSL < Minitest::Test end unless Puma.jruby? msg = /wrong version number|(unknown|unsupported) protocol|no protocols available|version too low|unknown SSL method/ - assert_match(msg, @events.error.message) if @events.error + assert_match(msg, @log_writer.error.message) if @log_writer.error end end @@ -189,7 +189,7 @@ class TestPumaServerSSL < Minitest::Test end unless Puma.jruby? msg = /wrong version number|(unknown|unsupported) protocol|no protocols available|version too low|unknown SSL method/ - assert_match(msg, @events.error.message) if @events.error + assert_match(msg, @log_writer.error.message) if @log_writer.error end end @@ -258,8 +258,8 @@ class TestPumaServerSSLClient < Minitest::Test app = lambda { |env| [200, {}, [env['rack.url_scheme']]] } - events = SSLEventsHelper.new STDOUT, STDERR - server = Puma::Server.new app, events + log_writer = SSLLogWriterHelper.new STDOUT, STDERR + server = Puma::Server.new app, log_writer server.add_ssl_listener host, port, CTX host_addrs = server.binder.ios.map { |io| io.to_io.addr[2] } server.run @@ -288,9 +288,9 @@ class TestPumaServerSSLClient < Minitest::Test # The JRuby MiniSSL implementation lacks error capturing currently, # so we can't inspect the messages here unless Puma.jruby? - assert_match error, events.error.message if error - assert_includes host_addrs, events.addr if error - assert_equal subject, events.cert.subject.to_s if subject + assert_match error, log_writer.error.message if error + assert_includes host_addrs, log_writer.addr if error + assert_equal subject, log_writer.cert.subject.to_s if subject end ensure server.stop(true) if server @@ -346,8 +346,8 @@ class TestPumaServerSSLWithCertPemAndKeyPem < Minitest::Test } app = lambda { |env| [200, {}, [env['rack.url_scheme']]] } - events = SSLEventsHelper.new STDOUT, STDERR - server = Puma::Server.new app, events + log_writer = SSLLogWriterHelper.new STDOUT, STDERR + server = Puma::Server.new app, log_writer server.add_ssl_listener host, port, ctx server.run diff --git a/test/test_response_header.rb b/test/test_response_header.rb index 508bbcd7..4c1edfd8 100644 --- a/test/test_response_header.rb +++ b/test/test_response_header.rb @@ -12,8 +12,8 @@ class TestResponseHeader < Minitest::Test @app = ->(env) { [200, {}, [env['rack.url_scheme']]] } - @events = Puma::Events.strings - @server = Puma::Server.new @app, @events + @log_writer = Puma::LogWriter.strings + @server = Puma::Server.new @app, @log_writer end def teardown diff --git a/test/test_web_server.rb b/test/test_web_server.rb index 9dc1093c..dea8117f 100644 --- a/test/test_web_server.rb +++ b/test/test_web_server.rb @@ -23,7 +23,7 @@ class WebServerTest < Minitest::Test def setup @tester = TestHandler.new - @server = Puma::Server.new @tester, Puma::Events.strings + @server = Puma::Server.new @tester, Puma::LogWriter.strings @port = (@server.add_tcp_listener "127.0.0.1", 0).addr[1] @tcp = "http://127.0.0.1:#{@port}" @server.run