1
0
Fork 0
mirror of https://github.com/puma/puma.git synced 2022-11-09 13:48:40 -05:00

SIGINFO prints thread backtraces (#1320)

This commit is contained in:
Nate Berkopec 2019-09-12 09:59:54 +00:00 committed by GitHub
parent 3ce98b7960
commit e96e798068
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 62 additions and 10 deletions

View file

@ -346,8 +346,8 @@ module Puma
log "+ Changing to #{dir}"
Dir.chdir dir
end
# Inside of a child process, this will return all zeroes, as @workers is only populated in
# Inside of a child process, this will return all zeroes, as @workers is only populated in
# the master process.
def stats
old_worker_count = @workers.count { |w| w.phase != @phase }

View file

@ -325,6 +325,17 @@ module Puma
log "- Goodbye!"
end
def log_thread_status
Thread.list.each do |thread|
@events.log "Thread TID-#{thread.object_id.to_s(36)} #{thread['label']}"
if thread.backtrace
@events.log thread.backtrace.join("\n")
else
@events.log "<no backtrace available>"
end
end
end
def set_process_title
Process.respond_to?(:setproctitle) ? Process.setproctitle(title) : $0 = title
end
@ -441,6 +452,15 @@ module Puma
rescue Exception
log "*** SIGHUP not implemented, signal based logs reopening unavailable!"
end
begin
Signal.trap "SIGINFO" do
log_thread_status
end
rescue Exception
# Not going to log this one, as SIGINFO is *BSD only and would be pretty annoying
# to see this constantly on Linux.
end
end
def require_rubygems_min_version!(min_version, feature)

View file

@ -97,7 +97,7 @@ class TestIntegration < Minitest::Test
end
# gets worker pids from @server output
def get_worker_pids(phase, size = WORKERS)
def get_worker_pids(phase = 0, size = WORKERS)
pids = []
re = /pid: (\d+)\) booted, phase: #{phase}/
while pids.size < size

View file

@ -8,6 +8,20 @@ class TestIntegrationCluster < TestIntegration
super
end
def test_siginfo_thread_print
skip_unless_signal_exist? :INFO
cli_server("-w #{WORKERS} -q test/rackup/hello.ru")
worker_pids = get_worker_pids
output = []
t = Thread.new { output << @server.readlines }
Process.kill(:INFO, worker_pids.first)
Process.kill(:INT, @server.pid)
t.join
assert_match "Thread TID", output.join
end
def test_usr2_restart
_, new_reply = restart_server_and_listen("-q -w #{WORKERS} test/rackup/hello.ru")
assert_equal "Hello World", new_reply
@ -92,7 +106,7 @@ class TestIntegrationCluster < TestIntegration
pid = cli_server("-w #{WORKERS} test/rackup/hello.ru").pid
# Get the PIDs of the child workers.
worker_pids = get_worker_pids 0
worker_pids = get_worker_pids
# Signal the workers to terminate, and wait for them to die.
Process.kill :TERM, pid

View file

@ -84,4 +84,17 @@ class TestIntegrationSingle < TestIntegration
assert_raises(Errno::ECONNREFUSED) { TCPSocket.new(HOST, @tcp_port) }
end
def test_siginfo_thread_print
skip_unless_signal_exist? :INFO
cli_server("test/rackup/hello.ru")
output = []
t = Thread.new { output << @server.readlines }
Process.kill(:INFO, @server.pid)
Process.kill(:INT, @server.pid)
t.join
assert_match "Thread TID", output.join
end
end

View file

@ -60,4 +60,14 @@ class TestLauncher < Minitest::Test
# assert no "/../" in path
refute_match(%r{/\.\./}, puma_wild_location)
end
def test_prints_thread_traces
events = Puma::Events.strings
l = Puma::Launcher.new(Puma::Configuration.new, events: events)
l.send(:log_thread_status)
events.stdout.rewind
assert_match "Thread TID", events.stdout.read
end
end

View file

@ -9,7 +9,7 @@ class TestPumaServer < Minitest::Test
@app = lambda { |env| [200, {}, [env['rack.url_scheme']]] }
@events = Puma::Events.new STDOUT, STDERR
@events = Puma::Events.strings
@server = Puma::Server.new @app, @events
end
@ -280,9 +280,6 @@ EOF
end
def test_doesnt_print_backtrace_in_production
@events = Puma::Events.strings
@server = Puma::Server.new @app, @events
@server.app = proc { |e| raise "don't leak me bro" }
@server.leak_stack_on_error = false
@server.add_tcp_listener @host, @port
@ -298,7 +295,6 @@ EOF
end
def test_prints_custom_error
@events = Puma::Events.strings
re = lambda { |err| [302, {'Content-Type' => 'text', 'Location' => 'foo.html'}, ['302 found']] }
@server = Puma::Server.new @app, @events, {:lowlevel_error_handler => re}
@ -314,7 +310,6 @@ EOF
end
def test_leh_gets_env_as_well
@events = Puma::Events.strings
re = lambda { |err,env|
env['REQUEST_PATH'] || raise("where is env?")
[302, {'Content-Type' => 'text', 'Location' => 'foo.html'}, ['302 found']]